POJ 1014 Dividing (多重可行性背包)

题意

有分别价值为1,2,3,4,5,6的6种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000

思路

裸的多重可行性背包,设dp[i]表示容量为i是否可装。状态设计看代码吧。

代码

  [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; int num[7]; bool dp[130000]; void zero_one_pack(int num, int V){ for (int i = V; i >= num; i --){ if (dp[i]) continue; if (dp[i-num]) dp[i] = true; } return ; } void complete_pack(int num, int V){ for (int i = num; i <= V; i ++){ if (dp[i]) continue; if (dp[i-num]) dp[i] = true; } return ; } void multi_pack(int num, int amount, int V){ if (num * amount >= V){ complete_pack(num, V); } int k = 1; while(amount > k){ zero_one_pack(k*num, V); amount -= k; k <<= 1; } zero_one_pack(amount*num, V); } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int t = 1; while(scanf("%d %d %d %d %d %d", &num[1], &num[2], &num[3], &num[4], &num[5], &num[6])){ if (num[1] + num[2] + num[3] + num[4] + num[5] + num[6] == 0){ break; } printf("Collection #%d: ", t); int sum = 0; for (int i = 1; i <= 6; i ++){ sum += num[i] * i; } if (sum % 2 != 0){ puts("Can't be divided."); puts(""); t ++; continue; } sum /= 2; MEM(dp, false); dp[0] = true; for (int i = 1; i <= 6; i ++){ multi_pack(i, num[i], sum); } if (dp[sum]){ puts("Can be divided."); } else{ puts("Can't be divided."); } puts(""); t ++; } return 0; } [/cpp]
原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114354.html