转载请注明出处:http://blog.csdn.net/u012860063
题目链接:http://poj.org/problem?id=1014
Description
Input
Output
Sample Input
1 0 1 2 0 0 1 0 0 0 1 1 0 0 0 0 0 0
Sample Output
Collection #1: Can't be divided. Collection #2: Can be divided.
Source
大致题意:
有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000
输出:每个测试用例占三行:
第一行: Collection #k: k为第几组测试用例
第二行:是否能分(具体形式见用例)
第三行:空白(必须注意,否则PE)
#include <cstdio> #include <iostream> #define INF 100000000 using namespace std; int f[240005]; //f[j]相当于f[i][j]: 考虑1...i个物品,恰好放到容量为j,所能达到的最大价值 int v; //背包容量 int max(int a,int b) { if(a > b) return a; return b; } //处理一个完全背包 (该种物品不限量) void complete_pack(int *a, int c, int w) { for(int i = c; i <= v; i++) a[i] = max(a[i], a[i - c] + w); } //处理一个 01背包 (该种物品只有一个) void zeroone_pack(int *a, int c, int w) { for(int i = v; i >= c; i--) a[i] = max(a[i], a[i - c] + w); } //处理一个多重背包 (该种物品指定上限) void mutiple_pack(int *a, int c, int w, int m) { //若该种物品足以塞满背包-->转化为完全背包 if(c * m >= v) { complete_pack(a, c, w); return; } /*二进制思想拆分:多重背包中的一个物品--变成-->0-1背包中的多个物品 容量:2^0 2^1 2^2 2^k m-∑前面 ***保证k达到最大值 价值:2^0*c 2^1*c 2^2*c 2^k*c (m-∑前面 )*c */ int k = 1; while(k <= m) { zeroone_pack(a, k * c, k * w); m = m - k; k = 2 * k; } } int main() { //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int sum, i, c[7], w[7], m[7],cas = 0; while(scanf("%d%d%d%d%d%d", &m[1], &m[2], &m[3], &m[4], &m[5], &m[6])) { if(m[1] == 0 && m[2] == 0 && m[3] == 0 && m[4] == 0 && m[5] == 0 && m[6] == 0) break; sum = 0; for(i = 1; i <= 6; i++) { c[i] = w[i] = i; sum += c[i] * m[i]; } printf("Collection #%d:\n", ++cas); if(sum %2 == 1) { printf("Can't be divided.\n\n"); } else { sum /= 2; v = sum; for(i = 1; i <= sum; i++) f[i] = -INF; f[0] = 0; for(i = 1; i <= 6; i++) mutiple_pack(f, c[i], w[i], m[i]); if(f[v] != v)//其实只要f[v]有正值就可以 { printf("Can't be divided.\n\n"); } else { printf("Can be divided.\n\n"); } } } return 0; }