題意
有分別價值爲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:\n", 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]