poj - 1014 - Dividing(多重背包)
来源:互联网 发布:阿里云如何获取推荐码 编辑:程序博客网 时间:2024/05/06 05:40
题意:价值为1,2,3,4,5,6的石子分别有n1,n2,n3,n4,n5,n6个,问能否把石子分成价值相等的两份(石子总个数 <= 20000)。
题目链接:http://poj.org/problem?id=1014
——>>转换为二进制拆分+01背包。。
二进制拆分:把第i种石子拆分成ni份,对于每一份,可取可不取,可用01背包,但这样时间开销较大。有这样一个事实:对于一个正整数n,小于等于n的任何一个正整数都可以用1, 2, 4, 8, 16, ..., 2^k, n-(2^(k+1)-1)中的几个数的和表示(想想n的二进制表示,小于等于n的正整数中,对于 <=2^k 的正整数,二进制位对应就是;对于 > 2^k 且 <= n 的正整数x,设前面的1 + 2 + 4 + 8 + 16 + ... + 2^k = s1, n-(2^(k+1)-1) = s2,则n = s1 + s2,则x = s1 + s2 - y,y是s1中某些数的和。),这样同样可以用01背包且时间开销减小了。。。
——>>将同一种石子重新分堆,分别分成2^0个,2^1个,2^2个,2^3个……
状态:设dp[i][j]为从前i堆石子取石子组成价值不超过 j 的最大价值是多少。
状态转移方程:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nVal[i]] + nVal[i]);
使用滚动数组优化为一维。。
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 20000 + 10;int w[maxn], cnt, d[maxn*6];void init() { cnt = 0;}void binary_split(int *a, int n) { for(int i = 1; i <= n; i++) { int sum = 0; for(int j = 1; sum+j <= a[i]; j <<= 1) { w[++cnt] = i * j; sum += j; } if(sum < a[i]) w[++cnt] = i * (a[i] - sum); }}bool dp(int sum) { memset(d, 0, sizeof(d)); for(int i = 1; i <= cnt; i++) { for(int j = sum; j >= 0; j--) if(j >= w[i]) d[j] = max(d[j], d[j-w[i]] + w[i]); } return d[sum] == sum;}int main(){ int a[7], kase = 0; while(scanf("%d%d%d%d%d%d", a+1, a+2, a+3, a+4, a+5, a+6) == 6) { if(!a[1] && !a[2] && !a[3] && !a[4] && !a[5] && !a[6]) return 0; printf("Collection #%d:\n", ++kase); int sum = 0; for(int i = 1; i <= 6; i++) sum += i * a[i]; if(sum&1) { puts("Can't be divided.\n"); } else { init(); binary_split(a, 6); dp(sum/2) ? puts("Can be divided.\n") : puts("Can't be divided.\n"); } } return 0;}
2014.9.24
#include <cstdio>#include <cstring>#include <algorithm>using std::max;const int MAXN = 6;const int MAXV = 100;const int MAXDP = 210000 + 10;int nCnt[MAXN + 1];int nVal[MAXV], nNewCnt;int dp[MAXDP];void Split(){ nNewCnt = 0; for (int i = 1; i <= MAXN; ++i) { for (int j = 1; nCnt[i] - j >= 0; nCnt[i] -= j, j <<= 1) { nVal[++nNewCnt] = i * j; } if (nCnt[i]) nVal[++nNewCnt] = i * nCnt[i]; }}bool ZeroOnePack(int target){ memset(dp, 0, sizeof(dp)); for (int i = 1; i <= nNewCnt; ++i) { for (int j = target; j >= 0; --j) { if (j >= nVal[i]) { dp[j] = max(dp[j], dp[j - nVal[i]] + nVal[i]); } } } return dp[target] == target;}int main(){ int nCase = 0; while (scanf("%d%d%d%d%d%d", nCnt + 1, nCnt + 2, nCnt + 3, nCnt + 4, nCnt + 5, nCnt + 6) == 6) { if (!nCnt[1] && !nCnt[2] && !nCnt[3] && !nCnt[4] && !nCnt[5] && !nCnt[6]) { break; } int nSumValue = 0; for (int i = 1; i <= MAXN; ++i) { nSumValue += i * nCnt[i]; } printf("Collection #%d:\n", ++nCase); if (nSumValue & 1) { puts("Can't be divided."); } else { Split(); ZeroOnePack(nSumValue >> 1) ? puts("Can be divided.") : puts("Can't be divided."); } puts(""); } return 0;}
0 0
- POJ 1014 Dividing (多重背包)
- POJ 1014 Dividing ( 多重背包)
- poj - 1014 - Dividing(多重背包)
- poj 1014 Dividing(多重背包)
- poj 1014 Dividing (多重背包模板)
- POJ 1014 Dividing(多重背包)
- 【POJ】 1014 Dividing(多重背包,优化)
- poj 1014 Dividing 多重背包
- Poj 1014 Dividing//多重背包
- Poj 1014 Dividing(多重背包)
- POJ 1014 Dividing 多重背包
- POJ 1014 Dividing 多重背包
- POJ 1014 Dividing (多重背包)
- POJ 1014 Dividing 多重背包
- POJ 1014 Dividing 多重背包
- poj 1014 Dividing 【多重背包】
- POJ 1014 Dividing(多重背包转换成01背包)
- zoj 1149 || poj 1014 Dividing(多重背包)
- c++中struct和class的区别
- 函数对象(函数符)
- WM_NCHITTEST 消息使用解说
- POJ 2449第K短路(A*+spfa)
- STL容器简介
- poj - 1014 - Dividing(多重背包)
- makefile 使用的函数
- Ajax向服务器端传递参数还有“+”和“&”处理办法
- RTTI 运行阶段类型识别
- java notes
- Pascal's Triangle
- 画笔
- Thinking in Java【笔记】
- 通过开源文档学LESS系列1