POJ1014 Dividing

来源:互联网 发布:mac日本价格 编辑:程序博客网 时间:2024/04/30 07:35
#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<memory.h>#include<queue>#include<stack>using namespace std;#define N 155#define MAX(a, b) a>b?a:bconst int size = 7;int dp[60010], amount[size];int volume;bool flag;void ZeroOnePack(int c, int w){for(int v = volume; v >= c; v--){ dp[v] = MAX(dp[v-c]+w, dp[v]);if(dp[v] == volume){flag = true;break;}}}int main(){int cas = 0, i, v, total;while(true){cas++;memset(dp, -1, sizeof(dp));dp[0] = 0;total = 0;flag = false; //标记是否可分for(i = 1; i < size; i++){scanf("%d", &amount[i]);total += i*amount[i];}if(total == 0) break;if(total%2 == 0) //一个剪枝,当价值为偶数时才有可能可分,否则,flag 为false。{            volume = total/2;  //背包容量为弹珠总价值的一半,题意就是能否将这个背包装满。            for(i = 1; i < size && !flag; i++){if(amount[i] == 0) continue;if(i*amount[i] >= volume){for(v = i; v <= volume; v++) //当价值为i的弹珠的总价值超过容量了,把问题转变成完全背包的问题。{dp[v] = MAX(dp[v-i]+i, dp[v]);if(dp[v] == volume) //当背包已经满了,直接跳出循环,停止DP{flag = true;break;}}continue;}/*当不为完全背包时,采用二进制优化(具体参见dd_engi的背包九讲),将多件相同的物品合成一件进行01背包,优化时间*/int k = 1;while(k < amount[i] && !flag) {ZeroOnePack(k*i, k*i);if(flag) continue;amount[i] -= k;k *= 2;}                ZeroOnePack(amount[i]*i, amount[i]*i); /*此处包含amount[i]为1和amount[i] > 1且amount[i]*i < volume的情况   (即不执行上面的while循环和执行while循环的两种情况)*/}}printf("Collection #%d:\n", cas);if(flag)printf("Can be divided.\n\n");else printf("Can't be divided.\n\n");}return  0;}

原创粉丝点击