您的位置:首页 > 其它

fzu 1877 Minisum [动态规划]

2010-06-19 15:31 225 查看
Fzu月赛题目,当时没做出来。
最小化Ans=Min{sum{ai*aj},其中遍历所有的i<j};
而ai 只考虑取a[i] 或者 -a[i];(这里不知道why了?)

考虑dp[i][j] : 前i个数可能组成的和为j时的 当前ans的最小值.
考虑数据范围,j可能的取值为[-4000 , 4000]。
因此为了不出现负数,加上定值M=4000。
那么dp[i+1][j+a[i+1]]=min(dp[i+1][j+a[i+1]],dp[i][j]+ (j-M)*a[i+1]);
dp[i+1][j-a[i+1]]=min(dp[i+1][j-a[i+1]],dp[i][j]+ (j-M)*(-a[i+1]));

小结:这是一种 长度上的线性动态规划。
要注意观察数据范围,设计出易于状态转移的状态方程。

]// fzu 1877 Minisum    Jun 19 ,Sat,14:50
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=50;
const int M=4000;
const int INF=0x5fffffff;

int N,a[MAX],dp[MAX][10000];
void DP()
{
int i,j;
dp[1][a[1]+M]=0;
dp[1][-a[1]+M]=0;

for(i=1;i<N;i++)
{
for(j=0;j<=8000;j++)
{
if(dp[i][j]==INF) continue;
dp[i+1][j+a[i+1]]=min(dp[i+1][j+a[i+1]],dp[i][j]+(j-M)*a[i+1]);
dp[i+1][j-a[i+1]]=min(dp[i+1][j-a[i+1]],dp[i][j]+(j-M)*(-a[i+1]));
}
}
}
int main()
{
int i,j;
while(scanf("%d",&N)==1)
{
for(i=1;i<=N;i++) scanf("%d",&a[i]);

for(i=1;i<=N;i++)
{
for(j=0;j<=8000;j++) dp[i][j]=INF;
}
DP();

int ans=INF;
for(i=0;i<=8000;i++) ans=min(ans,dp
[i]);
printf("%.2lf/n",(double)ans);
}
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: