dp之状态和状态转移 2

来源:互联网 发布:制作纪录片的软件 编辑:程序博客网 时间:2024/05/22 10:41
/*
题目1453:Greedy Tino
题目描述:
 Tino wrote a long long story. BUT! in Chinese...
So I have to tell you the problem directly and discard his long long story. That is tino want to carry some oranges with "Carrying pole", and he must make two side of the Carrying pole are the same weight. Each orange have its' weight. So greedy tino want to know the maximum weight he can carry.
输入:
The first line of input contains a number t, which means there are t cases of the test data.
for each test case, the first line contain a number n, indicate the number of oranges.
the second line contains n numbers, Wi, indicate the weight of each orange
n is between 1 and 100, inclusive. Wi is between 0 and 2000, inclusive. the sum of Wi is equal or less than 2000.
输出:
For each test case, output the maximum weight in one side of Carrying pole. If you can't carry any orange, output -1. Output format is shown in Sample Output.
样例输入:
1
5
1 2 3 4 5
样例输出:
Case 1: 7
*/
#include <stdio.h>       //输出空格,还有注释错误
#define OFFSET 2000 //因为柑橘重量差存在负数的情况,即第一堆比第二堆轻,
//所以在计算重量差对应数组下标时加上该偏移值,使每个重量差对应合法的数组下标
int dp[101][4001];//保存状态
int list[101];//保存柑橘数量
#define INF 0x7fffffff //无穷
int main(){
int T,i,j;
int cas = 0;//处理的case数,以便输出
scanf("%d",&T);//输入要处理的数据组数
while(T-- != 0){//T次循环
int n;
scanf("%d",&n);
bool havezero = false;//统计是否存在重量为0的柑橘
int cnt = 0;//计数器,记录共有多少个重量非零的柑橘
for(i=1;i<=n;i++){//输入n个柑橘重量
scanf("%d",&list[++cnt]);
if(list[cnt] == 0){//若当前输入柑橘重量为0
cnt--;//去除这个柑橘
havezero = true;//并记录存在重量为0的柑橘
}
}
n=cnt;
for(i=-2000;i<=2000;i++){
dp[0][i+OFFSET] = -INF;
}//初始化,所有dp[0][i]为负无穷,注意要对重量差加上OFFSET后读取或调用
dp[0][0+OFFSET] = 0;//dp[0][0]为0
for(i=1;i<=n;i++){//遍历每个柑橘
for(j=-2000;j<=2000;j++){//遍历每种可能的重量差
int tmp1 = -INF, tmp2 = -INF;
//分别记录当前柑橘放在第一堆或第二堆时转移得来的新值
//若无法移动则为-INF
if(j+list[i] <= 2000 && dp[i-1][j+list[i]+OFFSET] != -INF){
//当状态可以由放在第一堆转移而来时
tmp1 = dp[i-1][j+list[i]+OFFSET] + list[i];//记录转移值
}
if(j-list[i] >= -2000 && dp[i-1][j-list[i]+OFFSET] != -INF){
//当状态可以由放在第二堆转移而来时
tmp2 = dp[i-1][j-list[i]+OFFSET] + list[i];
//记录该转移值
}
if(tmp1 < tmp2){
tmp1 = tmp2;
}//取两者中较大的那个,保存至tmp1
if(tmp1 < dp[i-1][j+OFFSET]){//将tmp1与当前柑橘不放入任何
//堆即状态差不发生改变的原状态值比较,取较大的值保存至tmp1
tmp1 = dp[i-1][j+OFFSET];
}
dp[i][j+OFFSET] = tmp1;//当前值状态保存为三个转移来源转移得到的新值中最大的那个


}
}
printf("Case %d: ",++cas);//按题目要求输出
if(dp[n][0+OFFSET] == 0){//dp[n][0]为0
puts(havezero == true ? "0" : "-1");
//根据是否存在重量为0的柑橘输出0或-1
}
else printf("%d\n",dp[n][0+OFFSET]/2);//否则输出dp[n][0]/2




}//while


return 0;
}//main
0 0