POJ 1014 dividing(多重背包+二进制拆分)
来源:互联网 发布:高中生心理健康数据 编辑:程序博客网 时间:2024/04/29 21:43
今天终于整理完了堆积了好几天的多重背包了,一开始研究多重背包的时候开着解题思路很简单就是01背包稍微变化一下就行,但是我做了半天却是TimeLimited,查过之后才知道为了缩减时间开销需要二进制拆分,也没来得及弄,今天终于整理完了
多重背包就是变形的01背包,多重背包转换成 01 背包问题就是多了个初始化,只是把一样的物品拆分一下就好了,关键是一个叫二进制拆分的算法,感觉这个算法很好,在以后的时候能够用的着,所以有必要好好说说理解一下
把它的件数C 用分解成若干个件数的集合,这里面数字可以组合成任意小于等于C 的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可以用数字的二进制形式来解释比如:
7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以组合成任意小于等于7 的数,而且每种组合都会得到不同的数
15 = 1111 可分解成 0001 0010 0100 1000 四个数字如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。
案例:POJ 1014 dividing
一开始的没有用二进制拆分的算法,超时~~~
#include <iostream>using namespace std;int main (){ int a[6],count=1; int vol[20010],f[20010*6]; while ( scanf("%d %d %d %d %d %d",&a[0],&a[1],&a[2],&a[3],&a[4],&a[5])) { if( a[0]==0 && a[1]==0 && a[2]==0 && a[3]==0 && a[4]==0 && a[5]==0 ) break; int sum = a[0]+a[1]+a[2]+a[3]+a[4]+a[5]; if((a[0]+a[1]*2+a[2]*3+a[3]*4+a[4]*5+a[5]*6)%2)//如果总数为奇数,就直接判断 { printf("Collection #%d:\nCan't be divided.\n\n",count++); continue; } int divideAllValue = (a[0]+a[1]*2+a[2]*3+a[3]*4+a[4]*5+a[5]*6)/2; int w=0; int i,j; for( i=0; i<=5 ;i++) for( j=1 ; j<=a[i] ; j++)//把这a[i]件物品全部放进数组中 vol[w++] = i+1 ; memset(f,0,sizeof(f)); for(i = 0 ; i < sum ; i++) //遍历i件物品 { for(j = divideAllValue ; j >= vol[i] ; j--) { int tem = f[ j-vol[i] ] + vol[i]; if( f[j] < tem ) f[j] = tem; } } if(f[divideAllValue]==divideAllValue) printf("Collection #%d:\nCan be divided.\n\n",count++); else printf("Collection #%d:\nCan't be divided.\n\n",count++); } return 0;}
含二进制拆分的经典算法:
#include <iostream>#include <fstream>using namespace std;int a[6],allcase=1;int vol[20010],f[20010*6];int count;void divide(){ for(int i=0;i<6;i++) { for (int k=1; k<=a[i]; k<<=1) { //<<右移 相当于乘二 vol[count++] = k*(i+1); a[i] =a[i] - k; } if (a[i] > 0) vol[count++] = a[i] * (i+1); }}/*for( i=0; i<=5 ;i++)for( j=1 ; j<=a[i] ; j++)//把这a[i]件物品全部放进数组中vol[w++] = i+1 ; */int main (){ while (scanf("%d %d %d %d %d %d",&a[0],&a[1],&a[2],&a[3],&a[4],&a[5])) { count = 0; if( a[0]==0 && a[1]==0 && a[2]==0 && a[3]==0 && a[4]==0 && a[5]==0 ) break; int sum = a[0]+a[1]+a[2]+a[3]+a[4]+a[5]; if( (a[0]+a[1]*2+a[2]*3+a[3]*4+a[4]*5+a[5]*6)%2==1 )//如果总数为奇数,就直接判断 { printf("Collection #%d:\nCan't be divided.\n\n",allcase++); continue; } int divideAllValue = (a[0]+a[1]*2+a[2]*3+a[3]*4+a[4]*5+a[5]*6)/2; int i,j; memset(f,0,sizeof(f)); divide(); for(i = 0 ; i < count ; i++) //遍历i件物品 { for(j = divideAllValue ; j >= vol[i] ; j--) { int tem = f[ j-vol[i] ] + vol[i]; if( f[j] < tem ) f[j] = tem; } } if(f[divideAllValue]==divideAllValue) printf("Collection #%d:\nCan be divided.\n\n",allcase++); else printf("Collection #%d:\nCan't be divided.\n\n",allcase++); } return 0;}
0 0
- poj 1014 Dividing 多重背包 二进制拆分
- POJ 1014 dividing(多重背包+二进制拆分)
- POJ 1014 Dividing(二进制优化+多重背包)
- 【二进制拆分多重背包】【HDU1059】【Dividing】
- 1014 Dividing(多重背包 二进制划分)
- POJ 1014 Dividing(多重背包 + 二进制优化 + 01背包)
- 【POJ1014】Dividing 多重背包,二进制物品拆分转01背包
- POJ 1014 Dividing 【DP 之 多重背包 / 二进制优化】
- POJ 1014 Dividing (多重背包)
- POJ 1014 Dividing ( 多重背包)
- poj - 1014 - Dividing(多重背包)
- poj 1014 Dividing(多重背包)
- poj 1014 Dividing (多重背包模板)
- POJ 1014 Dividing(多重背包)
- 【POJ】 1014 Dividing(多重背包,优化)
- poj 1014 Dividing 多重背包
- Poj 1014 Dividing//多重背包
- Poj 1014 Dividing(多重背包)
- 还原数据库出现“未获得排他访问”解决方法(杀死数据库连接的存储过程sqlserver)
- 【阅读】《乔布斯的魔力演讲》
- (BestCoder Round #14) 1002 Harry And Dig Machine(状态压缩+DP;剪枝+搜索;全排列)
- WingIDE5注册破解的方法
- WP(文章大部分摘录自CSDN和博客园)
- POJ 1014 dividing(多重背包+二进制拆分)
- C#中的Dateset
- Android自动化测试2-Roboletric
- 关于Qt控制台程序
- stdafx 头中的STRICT定义说明
- iOS UITableView NSIndexPath属性讲解
- hdu 1050 Moving Tables(暴力)
- 利用SAE搭建微信公众平台(一)
- 《VC++深入详解》第四章 简单绘图