POJ 1014 Dividing
题目见此:http://poj.grids.cn/practice/1014
解题思路:
- 如果做过几道多重背包的题的话,很明显可以看出是用多重背包,V = 总数/2, N = 6, n数组就是不同大小大理石的个数。
- 我们可以采用“输出方案数”的做法:在背包中用sum,初始化f[0] = 1, f[其余] = 0, 最后只要考察f[V]的值是不是0(方案数是不是0)即可。
贴代码:
1 #include <iostream> 2 #include <string.h> 3 using namespace std; 4 #define sum(a, b) a+b 5 const int MAXN = 7, MAXV = 20020*3; 6 int f[MAXV], n[MAXN], N, V; 7 8 void Pack_01(int cost, int weigh) 9 { 10 for(int j=V ; j>=cost ; j--) 11 f[j] = sum(f[j], f[j-cost]); 12 } 13 void Pack_Com(int cost, int weigh) 14 { 15 for(int j=cost ; j<=V ; j++) 16 f[j] = sum(f[j], f[j-cost]); 17 } 18 void Pack_Mul(int cost, int weigh, int amount) 19 { 20 if(cost * amount >= V) 21 { Pack_Com(cost, weigh); return;} 22 for(int k=1 ; k<amount ; k=k<<1) 23 { 24 Pack_01(k*cost, k*weigh); 25 amount -= k; 26 } 27 Pack_01(amount*cost, amount*weigh); 28 } 29 30 int main() 31 { 32 int Case = 1; 33 N = 6; 34 while(1) 35 { 36 V = 0; 37 for(int i=1 ; i<=6 ; i++) 38 { cin >> n[i]; V += n[i] * c[i];} 39 if(V == 0) break; 40 cout << "Collection #" << Case++ << ":" << endl; 41 if(V % 2 == 1) {cout << "Can't be divided." << endl << endl; continue;} 42 memset(f, 0, sizeof(f)); 43 f[0] = 1; 44 V = V >> 1; 45 for(int i=1 ; i<=6 ; i++) 46 if(n[i]) 47 Pack_Mul(i, i, n[i]); 48 if(f[V]) 49 cout << "Can be divided." << endl << endl; 50 else 51 cout << "Can't be divided." << endl << endl; 52 } 53 }
如果熟悉背包的话,这题比较简单,注意把背包写对就行了
由于这是多重背包,所以可以用单调队列优化,但写起来比较麻烦。这里留一个没有用单调队列的,pku1276和pku1742我写了单调队列优化的方法。
期末程设一定要考背包啊!!!枉费我学了好几个晚上……
浙公网安备 33010602011771号