西电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

 

你可能感兴趣的:(dp)