西电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;
}
View Code

 

posted @ 2015-05-13 11:55  __560  阅读(714)  评论(0编辑  收藏  举报