给定n个数字,然后选择一些数字分成两堆,这两堆的和相等,求最大的和...
首先求一下所有数字的和...那么最后结果肯定小于等于sum/2。
然后范围50W...那么肯定滚动数组先,然后两数字的差当做第二维...
两数字的差要修正一下范围100W,遍历也要100W..然而可以并不需要,因为我们可以dp[i][j]代表选择前i个数字后两数字相差为j的最大值,那么最大值减去差值就是最小值。如果最小值加了某个数字大于最大值,可以换过来...
对于一个数字来言,可以放在第一个数字(不能爆sum),放在第二个数字(超过第一个数字or没超过)或者不选...
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
int dp[2][500200];
int a[60];
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
int n,sum=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sum=sum/2;
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
int s=1;
for(int i=0;i<n;i++)
{
s^=1;
for(int j=0;j<=sum;j++)
{
dp[s^1][j]=max(dp[s][j],dp[s^1][j]);
if(dp[s][j]==-1) continue;
if(j+a[i]<=sum)
dp[s^1][j+a[i]]=max(dp[s^1][j+a[i]],dp[s][j]+a[i]);//给大的数字加上大的...爆了sum就没意思了..
if(j>=a[i])
dp[s^1][j-a[i]]=max(dp[s^1][j-a[i]],dp[s][j]);//给小的数字加,没超过大的
else
dp[s^1][a[i]-j]=max(dp[s^1][a[i]-j],dp[s][j]+a[i]-j);//给小的数字加完超过大的了
}
}
printf("Case %d: ",cas);
if(dp[s^1][0]==0) printf("impossible\n");
else printf("%d\n",dp[s^1][0]);
}
return 0;
}