1036: 分配宝藏
时间限制: 1 Sec 内存限制: 128 MBhttp://acm.xidian.edu.cn/problem.php?id=1036
[ 提交 ][ 状态 ][ 讨论版 ]
题目描述
两个寻宝者找到一个宝藏,里面包含着n件物品,每件物品的价值是w[i]。suma代表寻宝者A所获物品的总价值,sumb代表寻宝者B所获物品的总价值,请问怎么分配,能使得|suma - sumb|(即suma与sumb之差的绝对值)最小。
输入
有多组输入数据,第一行为一个数字T,代表有T组输入数据 (0<T<=50)。
接下来为T组数据,每组数据分为两行:
第一行有一个整数n, 表示物品个数,其中0<n<=200.
第二行有n个整数,第i个正数w[i]代表第i件物品的价值,其中0<w[i]<=200.
注意:所有数据均为正整数。
输出
一共T行。
对于每组数据,输出一个整数,表示|suma-sumb|。
样例输入
2
2
2 3
4
1 2 3 4
样例输出
1
0
sum表示所有物品价值和,则若要两人获得物品的价值差最小,则需要其价值离sum/2最近
设获得物品价值较小的人获得的价值和为x,则x<=sum/2,就可以转为为以sum/2为背包容量的01背包
#include <cstdio>
#include <cstring>
using namespace std;
int T,n,sum,w[205],lim;
bool dp[20005];
int main() {
while(1==scanf("%d",&T)) {
while(T-->0) {
sum=0;
scanf("%d",&n);
for(int i=0;i<n;++i) {
scanf("%d",w+i);
sum+=w[i];
}
lim=sum>>1;//取总和的一半为背包容量上限
memset(dp,false,sizeof(dp));
dp[0]=true;
for(int i=0;i<n;++i) {
for(int j=lim;j>=w[i];--j) {
if(dp[j-w[i]])
dp[j]=true;
}
}
for(int i=lim;i>=0;--i) {
if(dp[i]) {//找到最大的可达到的sum
printf("%d\n",sum-i-i);
break;
}
}
}
}
return 0;
}