HDU 2191 珍惜现在,感恩生活。将多重背包经二进制划分变为01背包。
来源:互联网 发布:杨辉三角形 java 编辑:程序博客网 时间:2024/06/07 07:14
多重背包问题,不同种类的大米有不同的袋数,要求在资金有限的情况下获得重量最大值。
直接求解有些困难,我们可以换个角度思考:
针对某种 p元/h千克 共c袋的大米(我们可以给它们标记为第M0、M1、、、Mc袋大米),它可能出现(2的c次方)种情况,即对每一袋独立的大米Mi (i=0~c)来说,它可能取0也可能取1(取或不取)。这不正是01背包的思想吗?哪要管袋数的限制,统统拆分为独立的一袋统一进行01背包式求解。
我知道你已经灵光一现准备代码实现了。But wait,让我们分析一下时间复杂度:
O[((i=0~m)Σi(第i种大米的袋数))x(从n到0遍历)]=O(n^3)
嗯…n立方的复杂度,有点不能接受。能不能优化一下呢?答案当然是可以的:
我们注意到如果一件一件的拆分会存在大量重复计算。如对于 4袋1元/千克的大米 不论我们是选0001、0010、0100还是1000本质上是一样的都只是选了一袋。由0和1我们联想到二进制,而二进制数的表示是唯一的,我们为什么不干脆用二进制的方法划分大米呢?这样取x袋的组合数几乎是惟一的(因为袋数不可能完全符合2的n次方,多出部分可能构成与之前表示相同的结果),将大大精简运算。
如对于10袋相同大米,我们按 1、2、4、3划分为四部分,则取2袋的代码则为0100、取3袋为1100、4袋为0010等等。
由此我们大米袋数将减少至logn,复杂度优化为O(n*n*logn)
好了,我们来看一下代码实现吧:
#include <iostream>#include <cstdio>#include <cstdlib>#include <memory.h>#include <cstring>#include <queue>#include <cmath>#include <algorithm>#define IN freopen("in.txt", "r", stdin)#define OUT freopen("out.txt", "wb", stdout)#define max(a, b) (((a) > (b)) ? (a) : (b))#define min(a, b) (((a) < (b)) ? (a) : (b))#define N 110using namespace std;/** 采取二进制拆解,复杂度为O((n*logn)*n)即 种类*价格*/struct node{ int price; int weight;};node rice[N*7]; //由于一种大米最多有100袋,则最多拆解为log2(100)=7次,即100种大米最多拆解为 100*7=700 袋大米int ri,n,m,p,h,c; //ri用于记录已经记录了多少种大米了、n:经费、m:大米种类、p:单价、h:重量、c:对应袋数int weight[N]; //weight[i]表示在 i元经费的情况下所能获得的最大重量//函数功能:对该种类大米进行二分拆解void binary(){ int temp,found; for(found=1;c>0;found*=2) { c-=found; if(c<0) //剩余袋数不满足2的n次方了 found+=c; rice[ri].price=p*found; rice[ri].weight=h*found; ri++; }}int main(){ int t,i,j,con; //con用于记录最终结果 cin>>t; while(t-->0) { cin>>n>>m; memset(weight,0,sizeof(int)*(n+1)); ri=con=0; //设置初值 while(m-->0) { //读入大米信息并二分划分 cin>>p>>h>>c; binary(); } for(i=0;i<ri;i++) for(j=n;j>=0;j--) if(j-rice[i].price>=0 && weight[j] < weight[j-rice[i].price]+rice[i].weight ) { //状态转移方程:weight[j] = max(weight[j], weight[j-rice[i].price]+rice[i].weight ); weight[j] = weight[j-rice[i].price]+rice[i].weight; if(weight[j]>con) con=weight[j]; } cout<<con<<endl; } return 0;}
0 0
- HDU 2191 珍惜现在,感恩生活。将多重背包经二进制划分变为01背包。
- Hdu 2191 珍惜现在,感恩生活 (多重背包)
- HDU 2191 珍惜现在,感恩生活(多重背包)
- [ACM] hdu 2191 珍惜现在,感恩生活 (多重背包)
- HDU 2191 珍惜现在,感恩生活(多重背包)
- HDU 2191 珍惜现在,感恩生活 (多重背包)
- HDU 2191 珍惜现在,感恩生活 多重背包 .
- HDU-2191 珍惜现在,感恩生活(多重背包,二进制优化)
- 珍惜现在,感恩生活(多重背包)
- 珍惜现在,感恩生活-多重背包问题
- HDU 2191 珍惜现在感恩生活(01背包)
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(二进制优化 多重背包)
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(01背包,多重背包)
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包转01背包)
- HDOJ 2191 珍惜现在,感恩生活(多重背包)
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 多重背包
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
- HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 多重背包
- js判断对象类型 typeof与Object.prototype.toString.call方法的区别
- 如何repo下载google源码到移动硬盘?菜鸟求教。
- Dbvisualizer 打开过程中出现如下错误
- 2016年技术学习总结+2017年技术学习计划
- php安装扩展的几种方法
- HDU 2191 珍惜现在,感恩生活。将多重背包经二进制划分变为01背包。
- Android实际调用WebService时发生OOM错误
- Android studio .9图片报错
- Android6.0 控件显示不正常
- android 实现息屏状态下物理按键的监听
- java面试题集锦
- reactjs(二):三元运算
- Android 4.4 高通平台如何修改Contacts的Menu中字体大小?
- [Android 知识点] RxAndroid的使用(一)