题面
题意
给出n(n<=50)个数(每个数<=500000),选择其中一些并分成两组,使得两组的和相等问这个和最大是多少.
做法
dp,dp[i][j]表示考虑到第i个数时,较大的和与较小的和相差j,较小值为dp[i][j],则每次仅包括三种转移方式:
1.不取
dp[i][j]=max(dp[i][j],dp[i-1][j]);
2.加入较小的一组:
dp[i][abs(j-num[i])]=max(dp[i-1][j]+j*(num[i]>=j)+num[i] *(num[i]< j),dp[i][abs(j-num[i])]);
注意考虑较小值是否会变为较大值
3.加入较大的一组
dp[i][j+num[i]]=max(dp[i][j+num[i]],dp[i-1][j]);
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500000
using namespace std;
int n,m,num[60],dp[60][N/2+100];
int main()
{
memset(dp,-1,sizeof(dp));
int i,j;
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
dp[0][0]=0;
for(i=1;i<=n;i++)
{
for(j=0;j<=N/2;j++)
{
if(dp[i-1][j]==-1) continue;
dp[i][j]=max(dp[i][j],dp[i-1][j]);
dp[i][abs(j-num[i])]=max(dp[i-1][j]+j*(num[i]>=j)+num[i]*(num[i]<j),dp[i][abs(j-num[i])]);
if(dp[i-1][j]+j+num[i]<=N/2)
{
dp[i][j+num[i]]=max(dp[i][j+num[i]],dp[i-1][j]);
}
}
}
if(dp[n][0]) cout<<dp[n][0];
else cout<<-1;
}