西电oj 1036 dp(01背包)
西电oj 1036 dp(01背包)
1036: 分配宝藏
时间限制: 1 Sec 内存限制: 128 MB提交: 40 解决: 11
[提交][状态][讨论版]
题目描述
两个寻宝者找到一个宝藏,里面包含着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
思路:这题就是01背包的变种,一开始傻逼的去二进制枚举,直接TLErush。。。
dp(i,j)表示第i次取了重量j到A中A-B的差值,状态转移方程abs(dp(i,j))=min(abs(dp(i-1,j-w[i])+2*w[i]),abs(dp(i-1,j));
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<math.h> using namespace std; const int maxn=31000; const int INF=(1<<29); int T; int n,w[maxn]; int dp[310][maxn]; int sum; int main() { cin>>T; while(T--){ cin>>n; sum=0; for(int i=1;i<=n;i++){ scanf("%d",&w[i]); sum+=w[i]; } memset(dp,0,sizeof(dp)); for(int i=0;i<=sum;i++) dp[0][i]=-sum; for(int i=1;i<=n;i++){ for(int j=0;j<=sum;j++){ if(j-w[i]>=0){ int a=dp[i-1][j-w[i]]+2*w[i]; int b=dp[i-1][j]; if(abs(a)<abs(b)) dp[i][j]=a; else dp[i][j]=b; } else dp[i][j]=dp[i-1][j]; } } int ans=INF; for(int i=0;i<=sum;i++){ if(abs(dp[n][i])<ans) ans=abs(dp[n][i]); } cout<<ans<<endl; } return 0; }
没有AC不了的题,只有不努力的ACMER!