题意:输入六个数,价值分别为1——6,输入的数代表该价值的物品的个数;求能否平均分。
key:如果奇数肯定不能分,直接输出答案。偶数的话,就是多重背包问题。 试过两种做法,第一种是背包九讲的二进制优化,写三个函数,分别是bag01, bagall, bagmulti~第二种是直接多重背包~
#include <iostream> #include <algorithm> #include <string.h> #include <stdio.h> const int maxn = 120000 + 6; //20000 * 6 int dp[maxn]; int val[8]; //输入的六组数 int sum, sumh; using namespace std; void bag01(int w, int v) //01背包 { for(int i = sumh; i >= w; i--) if(dp[i] < dp[i - w] + v) dp[i] = dp[i - w] + v; } void allbag(int w, int v) //完全背包 { for(int i = w; i <= sumh; i++) if(dp[i] < dp[i - w] + v) dp[i] = dp[i - w] + v; } void multibag(int w, int v, int n) //多重背包,“背包九讲”有模版 { if(w * n >= sumh) //假如重量 * 数量,大于背包,就变成完全背包的情况,即该物品可任意取 allbag(w, v); else{ //进行二进制优化 int k = 1; while(k < n){ bag01(k * w, k * v); n = n - k; k = 2 * k; } bag01(w * n, v * n); } } int main() { int t = 1; while(scanf("%d%d%d%d%d%d", &val[1], &val[2], &val[3], &val[4], &val[5], &val[6]) != EOF){ memset(dp, 0, sizeof(dp)); sum = val[1] + val[2] * 2 + val[3] * 3 + val[4] * 4 + val[5] * 5 + val[6] * 6; if(sum == 0) break; sumh = sum / 2; if(sum % 2 != 0){ //奇数的话可直接输出不能 printf("Collection #%d:\n", t); printf("Can't be divided.\n\n"); t++; continue; } else{ for(int i = 1; i <= 6; i++){ //多重背包 multibag(i, i, val[i]); } if(dp[sumh] == sumh){ printf("Collection #%d:\n", t); printf("Can be divided.\n\n"); t++; } else{ printf("Collection #%d:\n", t); printf("Can't be divided.\n\n"); t++; } } } return 0; }
这是第二种做法!
#include <iostream> #include <stdio.h> #include <string.h> const int maxn = 120000 + 6; //20000 * 6 int dp[maxn]; int val[8]; //输入的六组数 int sum, sumh; using namespace std; int main() { int t = 1; while(scanf("%d%d%d%d%d%d", &val[1], &val[2], &val[3], &val[4], &val[5], &val[6]) != EOF){ memset(dp, 0, sizeof(dp)); sum = val[1] + val[2] * 2 + val[3] * 3 + val[4] * 4 + val[5] * 5 + val[6] * 6; if(sum == 0) break; sumh = sum / 2; if(sum % 2 != 0){ //奇数的话可直接输出不能 printf("Collection #%d:\n", t); printf("Can't be divided.\n\n"); t++; continue; } else{ for(int i = 1; i <= 6; i++){ //多重背包 int cnt[maxn]; //用来表示第J个背包里含有的I物品的数量 memset(cnt, 0, sizeof(cnt)); for(int j = i;j <= sumh; j++){ if(cnt[j - i] + 1 <= val[i] && i + dp[j - i] > dp[j]){ dp[j] = i + dp[j - i]; cnt[j] = cnt[j - i] + 1; } } } if(dp[sumh] == sumh){ printf("Collection #%d:\n", t); printf("Can be divided.\n\n"); t++; } else{ printf("Collection #%d:\n", t); printf("Can't be divided.\n\n"); t++; } } } return 0; }