poj1014 Dividing 动态规划 多重背包问题

来源:互联网 发布:内外网切换软件下载 编辑:程序博客网 时间:2024/06/08 18:33

第一次写多重背包的题,竟然1A,我真的十分地感动,哈哈。

题意:Marsha 和 Bill 收集了一些弹珠,弹珠因为大小和花纹不同,有不同的价值,他们想把弹珠分成价值相同的两份,这样对两个人才公平,

           问是否能够分成这样的两份。

#include <iostream>using namespace std;#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;}


 

 

 

原创粉丝点击