Poj--1014(多重背包)
2014-11-28 01:51:24
思路:多重背包启蒙题,一开始用01背包和dfs乱搞都T了,后来看了多重背包,然后自己YY了下,A掉了。
把每组物品的n,分解成系数:1,2^1,2^2 ... 2^(k-1) , n - 2^k + 1,我们知道:1+2^1+..+2^(k-1) = 2^k - 1,所以所有系数和为n,又因为数的二进制分解原理,所以1...n中任何一个整数都能表示成几个系数的和。
预处理下每组物品的系数即可。
1 /************************************************************************* 2 > File Name: p1014.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Thu 27 Nov 2014 11:21:14 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <stack> 16 #include <queue> 17 #include <iostream> 18 #include <algorithm> 19 using namespace std; 20 #define lp (p << 1) 21 #define rp (p << 1|1) 22 #define getmid(l,r) (l + (r - l) / 2) 23 #define MP(a,b) make_pair(a,b) 24 typedef long long ll; 25 const int INF = 1 << 30; 26 const int maxn = 60000; 27 28 int num[10]; 29 int dp[maxn + 10]; 30 int val[10][100],cnt[10]; 31 int sum; 32 33 void Pre(){ 34 for(int i = 1; i <= 6; ++i){ 35 int n = num[i]; 36 cnt[i] = 0; 37 for(int k = 1; k <= n; k <<= 1){ 38 val[i][++cnt[i]] = k * i; 39 n -= k; 40 } 41 if(n > 0){ 42 val[i][++cnt[i]] = n * i; 43 } 44 } 45 } 46 47 int main(){ 48 int Case = 0; 49 while(~scanf("%d%d%d%d%d%d",num + 1,num + 2,num + 3,num + 4,num + 5,num + 6)){ 50 sum = 0; 51 for(int i = 1; i <= 6; ++i){ 52 sum += i * num[i]; 53 } 54 if(sum == 0) 55 break; 56 printf("Collection #%d:\n",++Case); 57 if(sum % 2){ 58 printf("Can't be divided.\n\n"); 59 continue; 60 } 61 sum /= 2; 62 Pre(); 63 memset(dp,0,sizeof(dp)); 64 for(int i = 1; i <= 6; ++i){ 65 for(int o = 1; o <= cnt[i] ; ++o){ 66 for(int j = sum; j >= val[i][o]; --j){ 67 dp[j] = max(dp[j],dp[j - val[i][o]] + val[i][o]); 68 } 69 } 70 } 71 if(dp[sum] == sum) 72 printf("Can be divided.\n\n"); 73 else 74 printf("Can't be divided.\n\n"); 75 } 76 return 0; 77 }