hdu1171 二進制優化揹包問題

Big Event in HDU

Problem Description

Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don’t know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0

Input

Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 – the total number of different facilities). The next N lines contain an integer V (0

Output

For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.

Sample Input

2
10 1
20 1
3
10 1
20 2
30 1
-1

Sample Output

20 10
40 40

題意:給定n個物品,個數爲num,價值爲value,將總價值分成兩部分,其實儘可能的接近。
思路:揹包問題。dp[j]表示價值爲j是否存在。
轉移方程dp[j]|=dp[j-v[i]];
坑:從sum/2 開始找,如果是奇數則先輸出小再輸出大。

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=55,M=105;
int n,m;
int v[N*10];
int dp[N*N*M];
int main()
{
    while(scanf("%d",&n)!=EOF){
            if(n<0)break;
            int sum=0;
            int num,cnt=0,value;
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                scanf("%d%d",&value,&num);
                sum+=value*num;
                int t=1;
                while(num>t){
                    v[++cnt]=t*value;
                    num-=t;
                    t<<=1;
                }
                v[++cnt]=num*value;
            }
            dp[0]=1;
            for(int i=1;i<=cnt;i++)
                for(int j=sum;j>=v[i];j--){
                   dp[j]|=dp[j-v[i]];
                }
            for(int i=sum/2;i>=0;i--)//從中間往小找
            {
                if(dp[i]){
                    printf("%d %d\n",sum-i,i);
                    break;
                }
            }
          /*  int i;
            i=sum%2?(sum/2+1):(sum/2);//從中間往大的找要這麼處理。
            for(;i<=sum;i++){
                if(dp[i]==1){
                    printf("%d %d\n",i,sum-i);
                    break;
                }
            }
            */
    }
    return 0;
}
發佈了64 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章