
双塔DP。
dp[i][j]表示前i个物品,分成两堆(可以不全用),价值之差为j的时候,较小一堆的价值为dp[i][j]。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std; int dp[][ + ];
int a[];
int n, sum; void read()
{
for (int i = ; i <= n; i++) scanf("%d", &a[i]);
} void work()
{
sum = ;
for (int i = ; i <= n; i++) sum = sum + a[i];
memset(dp, -, sizeof dp);
int h; h = a[];
dp[][h + sum] = dp[][ - h + sum] = dp[][sum] = ;
for (int i = ; i <= n; i++)
{
h = a[i];
for (int j = ; j <= sum*; j++) dp[i][j] = dp[i - ][j];
for (int j = ; j <= sum*; j++)
{
if (dp[i - ][j] == -) continue; int tmp = j - sum;
if (tmp >= )
{
dp[i][h + tmp + sum] = max(dp[i][h + tmp + sum], dp[i - ][j]);
dp[i][tmp - h + sum] = max(dp[i][tmp - h + sum], dp[i - ][j] + min(tmp, h));
}
else if (tmp<)
{
tmp = -tmp;
dp[i][ - (tmp + h) + sum] = max(dp[i][ - (tmp + h) + sum], dp[i - ][j]);
dp[i][h - tmp + sum] = max(dp[i][h - tmp + sum], dp[i - ][j] + min(tmp, h));
}
}
}
int ans = ;
for (int i = ; i <= n; i++) ans = max(ans, dp[i][sum]);
if (ans == ) printf("Sorry\n");
else printf("%d\n", ans);
} int main()
{
while (~scanf("%d", &n))
{
read();
if (n < ) break;
if (n <=) printf("Sorry\n");
else work();
}
return ;
}