九度oj-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

样例输出:

7

解题思路:

这个题最重要的是找好状态,状态的定义很关键。设dp[i][j]表示前i个橘子中左边hole的重量比右边hole里多j时两边的总重量(默认是正的,右边比左边多时j为负值)。我们要求的即是dp[n][0]/2,除以2是表示一边的重量,平衡时两边重量相等,其次设每个橘子重量为a[i]。

现在关键就是找dp[i][j]和它上一个状态的关系。如果上一个状态之后,还要往这两个hole里面加橘子,则:dp[i][j]=max{dp[i][j-a[i]]+a[i],dp[i][j+a[i]]+a[i]};如果上一个状态之后,不往这两个hole里面放橘子,则:dp[i][j]=dp[i-1][j]。所以总体来说递推关系为:dp[i][j]=max{dp[i][j-a[i]]+a[i],dp[i][j+a[i]]+a[i],dp[i-1][j]}

然后这个题还要考虑一个特殊情况,就是什么时候输出-1。按直觉来说就是dp[n][0]=0时,也就表示n个橘子中,满足左右两边的重量相等时,总重量为0,表示没有找到合适的橘子。但是,由于题目中给定,每个橘子的重量可能是0,此时dp[n][0]=0就不一定表示没有找到合适的橘子,所以直接输出-1是有问题的(试想左右两边的hole,一个啥也没装,一个装了0kg的橘子,也是满足dp[n][0]=0的,这时候应该输出0)。所以质量为0的橘子应该单独考虑。

# include<stdio.h>

# define INF 1000000
# define OFFSET 2000
int dp[101][4001];//状态
int a[101];//橘子重量
int main()
{
   int t;
   scanf("%d",&t);
   int Case=0;

   while(t--)
   {
       int n,i,j;
	   scanf("%d",&n);

	   bool haveZero=false;
	   int index=0;

       for(i=1;i<=n;i++)//巧妙的排除质量为0的橘子,下标从1开始到n结束
	   {
	     scanf("%d",&a[++index]);//记得排除重量为0的橘子,++index先将index+1再使用新的index
		 if(a[index]==0)
		 {
			 index--;//舍弃当前质量为0的橘子
			 haveZero=true;
		 }
	   }
	   //初始化dp[i][j]
	   for(i=0;i<4001;i++)
		   dp[0][i]=-INF;//即不存在这种情况,要求最大值,先全部置成最小值
	   dp[0][0+OFFSET]=0;//将dp[0][0]设成0

	   //printf("%d\n",index);

	   for(i=1;i<=index;i++)
	   {
		   for(j=-2000;j<=2000;j++)
		   {
			   int tmp1=-INF;
			   int tmp2=-INF;
			   if(j-a[i]>=-2000&&dp[i-1][j-a[i]+OFFSET]!=-INF)
			   {
				   tmp1=dp[i-1][j-a[i]+OFFSET]+a[i];
			   }
			   if(j+a[i]<=2000&&dp[i-1][j+a[i]+OFFSET]!=-INF)
			   {
			       tmp2=dp[i-1][j+a[i]+OFFSET]+a[i];
			   }
			   if(tmp1<tmp2)
			   {
				   tmp1=tmp2;//最大值保存在tmp1里
			   }
			   if(tmp1<dp[i-1][j+OFFSET])
			   {
				   tmp1=dp[i-1][j+OFFSET];//和之前的值比较
			   }

			   dp[i][j+OFFSET]=tmp1;

		   }
	   }
       
	   printf("Case %d:\n",++Case);

	   if(dp[index][0+OFFSET]==0)//分两种情况
	   {
		   if(haveZero==true)
			   printf("0\n");
		   else
			   printf("-1\n");
	   }
	   else
	   {
		   printf("%d\n",dp[index][0+OFFSET]/2);//
	   }
   }

return 0;
}

 

 

 

posted @ 2018-04-08 21:44  xzhws  阅读(74)  评论(0编辑  收藏  举报