传送门:
1、题目:洛谷:kas
题目描述:
Kile和 Pogi在逛街的时候,捡到N张纸币。确定了无法找到失主之后,他俩决定分了这些钱。他们希望俩人分得的金额相同,所以他俩用这样的方式分钱。如果这些纸币可以被均分,那是最好不过了。可是分到最后,俩人分的金额有可能不同(尽量多的均分),而谁也不愿意是被分少的那一个。
他们也不可能把分不匀的钞票丢掉,于是他俩决定到最近的赌场去,他俩把剩余的钱都压上,两个小伙伴的运气实在是太好了,他们最终得到两倍的赌注。这样,两个小伙伴就能把他俩赢的钱均分成两份了。
由于好事来的太突然了,以至于这两个孩子已经失去了数学能力。请你帮助他们计算出他俩每个人能带回家多少钱。
输入格式:
第 1 行输入包含一个整数N,表示纸币的张数;
接下来的N行,每行包含一个正整数Ci表示第 i 张纸币的价值。
输出格式:
输出共一行一个整数,输出他俩每人能带回家多少钱。
样例输入:
样例1 4 2 3 1 6 样例2 5 2 3 5 8 13
样例输出:
样例1 6 样例2 18
提示:
【样例1说明】Kile将得到纸币2,3,1,Pogi将得到纸币6。
【样例2说明】Kile得到了纸币5和8,Pogi得到了纸币13。剩下的纸币是2和3,两个小伙伴在赌场中翻倍得到了2,2,3,3。所以每个人得到的钱是13+5=18。
【数据规模】
对于50%的数据: 1≤N≤15;
对于70%的数据: 1≤N≤50;所有纸币的总数不超过1,000;
对于100%的数据:1≤N≤500;所有纸币的总数不超过100,000;
提供思路答案:
注释请参考:
#include<bits/stdc++.h>
using namespace std;
int n,x,sum;
int dp[505][100005];
int main(){
scanf("%d",&n);
//dp[i][j]表示用前i张钱令两人取的钱的差值为j的取的钱的总和最大值。
memset( dp,-0x3f,sizeof(dp) );//这里为何要清负数?
//因为可能你在转移的时候,有一些DP的值根本没有更新。
dp[0][0]=0;
for (int i = 1;i <= n;i ++){
scanf ("%d", &x);
sum += x;
for(int j = 0; j <= sum; j ++){
dp[i][j] = dp[i - 1][j];
if ( dp[i - 1][j + x] + x > dp[i][j])
dp[i][j] = dp[i - 1][j + x] + x;
if ( j >= x && dp[i - 1][ j - x ] + x > dp[i][j])
dp[i][j] = dp[i - 1][j - x ] + x;
if ( x >= j && dp[i - 1][ x - j ] + x > dp[i][j])
dp[i][j] = dp[i - 1][ x - j ] + x;
}
}
printf( "%d", sum - dp[n][0] / 2 );
}