HDU 1171 Big Event in HDU (多重bool背包) /(01背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1171

Big Event in HDU

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 16791    Accepted Submission(s): 5908


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<N<1000) kinds of facilities (different value, different kinds).
 
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<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.
 
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
 

解题方案:我的方案是把多重背包转化为01背包,背包的体积就是总和的一半,然后我们要尽可能的把背包放满:网上有大牛用母函数写的,比较一下差别:

Run ID Submit Time Judge Status Pro.ID Exe.Time Exe.Memory Code Len. Language Author
8310536 2013-05-15 Accepted 1171 31MS 392K 1295 B G++ 大牛的
8310472 2013-05-15 Accepted 1171 2125MS 1332K 837 B G++ 我的

那时间和内存开销差距!!!

我的解题代码:

 1 // File Name: Big Event in HDU 1171.cpp
 2 // Author: sheng
 3 // Created Time: 2013年05月15日 星期三 19时53分07秒
 4 
 5 #include <stdio.h>
 6 #include <iostream>
 7 #include <string.h>
 8 using namespace std;
 9 
10 const int max_n = 5010;
11 int dp[250005];//数组大小50×100×50
12 int va[max_n];
13 
14 int main ()
15 {
16     int n, t, v;
17     int sum;
18     while (~scanf ("%d", &n) && n >= 0)
19     {
20         sum = 0;
21         int cun = 0;
22         memset (dp, 0, sizeof (dp));
23         while (n--)
24         {
25             scanf ("%d %d", &v, &t);
26             for (int i = 0; i < t; i ++)
27             {
28                 va [cun++] = v;
29             }
30             sum += v*t;
31         }
32         for (int i = 0; i < cun; i ++)
33         {
34             for (int j = sum/2; j >= va[i]; j --)
35             {
36                 dp[j] = max (dp[j], dp[j-va[i]] + va[i]);
37             }
38         }
39         printf ("%d %d\n", sum - dp[sum/2], dp[sum/2]);
40     }
41     return 0;
42 }
View Code G++

大牛的代码:(以后再来理解) 模型:给出n个数,从中选出若干个数相加得到一个新数,求新数的集合

 1 #include<iostream>
 2 #include<stdio.h>
 3 using namespace std;
 4 
 5 //可以看作有a[i]张i元钱,i=1..n;尽量把它们分成相差最小的两份
 6 //f[i]表示可否凑出i元,若有k元且f[i]==1->f[i+k]==1,因为只有一个转移状态,且状态可以叠加(不用清空再来),所以不必用2个数组,可以从后往前更新,
 7 //若从前往后找有些更新的状态会干扰以后的状态 
 8 const int N = 50;
 9 
10 bool f[250000/2+1];
11 
12 int money[N+1],ge[N+1];
13 
14 int main()
15 {
16     int i,j,k,n,m,total,keep_total;
17     while(scanf("%d", &n), n >= 0)
18     {
19         total = 0;
20         for(i = 1; i <= n; i ++) 
21         { 
22             scanf("%d%d", money+i, ge+i); 
23             total += money[i] * ge[i];
24         }
25         keep_total = total;
26         total = total/2;         //若前半部分可以凑出,那么后半部分肯定可以,所以只要考虑前半部分就行了 
27         for(i = 1; i <= total; i++)
28             f[i] = 0;
29         f[0] = 1;
30         for( k = 1; k <= n; k ++)// 多少类
31         {
32             for(j = 1; j * 2 - 1 <= ge[k]; j = j * 2)   //每类几件,优化:只需让循环中取得的若干个j之和刚好可以表示从1..ge[k]的每个数,不可多一个,故用2进制 
33             {
34                 for(i = total; i >= j * money[k]; i--)
35                     f[i] |= f[i - j*money[k]];
36             }
37             j = ge[k] - (j-1);   //剩下的 
38             if( j > 0)
39             {
40                 for(i = total; i >= j * money[k]; i--)
41                     f[i] |= f[i-j*money[k]];
42             }
43         }
44         for(i = total; i >= 0; i --)
45         {
46             if( f[i] ) 
47             {
48                 cout<<keep_total-i<<' '<<i<<endl;
49                 break;
50             }
51         }
52     }
53     return 0;
54 }
View Code G++
原文地址:https://www.cnblogs.com/shengshouzhaixing/p/3080853.html