多重揹包二進位制分解思想講解
轉載自http://blog.csdn.net/jkay_wong/article/details/7240588
在揹包九講裡面將多重揹包轉化為01揹包,並且進行時間優化,有利用到一個二進位制分解的思想。
下面是在網上搜尋之後得到的一個關於二進位制分解思想的講解和實現
- /**
- 在這之前,我空間好像轉過一個揹包九講,現在我就只對
- 01揹包和多重揹包有點印象了
- 先說下 01 揹包,有n 種不同的物品,每個物品有兩個屬性
- size 體積,value 價值,現在給一個容量為 w 的揹包,問
- 最多可帶走多少價值的物品。
- int f[w+1]; //f[x] 表示揹包容量為x 時的最大價值
- for (int i=0; i<n; i++)
- for (int j=w; j>=size[i]; j++)
- f[j] = max(f[j], f[j-size[i]]+value[i]);
- 如果物品不計件數,就是每個物品不只一件的話,稍微改下即可
- for (int i=0; i<n; i++)
- for (int j=size[i]; j<=w; j++)
- f[j] = max(f[j], f[j-size[i]]+value[i]);
- f[w] 即為所求
- 初始化分兩種情況
- 1、如果揹包要求正好裝滿則初始化 f[0] = 0, f[1~w] = -INF;
- 2、如果不需要正好裝滿 f[0~v] = 0;
- 多重揹包問題要求很簡單,就是每件物品給出確定的件數,求
- 可得到的最大價值
- 多重揹包轉換成 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 揹包求解了。
- 看程式碼:
- int n; //輸入有多少種物品
- int c; //每種物品有多少件
- int v; //每種物品的價值
- int s; //每種物品的尺寸
- int count = 0; //分解後可得到多少種物品
- int value[MAX]; //用來儲存分解後的物品價值
- int size[MAX]; //用來儲存分解後物品體積
- scanf("%d", &n); //先輸入有多少種物品,接下來對每種物品進行分解
- while (n--) { //接下來輸入n中這個物品
- scanf("%d%d%d", &c, &s, &v); //輸入每種物品的數目和價值
- for (int k=1; k<=c; k<<=1) { //<<右移 相當於乘二
- value[count] = k*v;
- size[count++] = k*s;
- c -= k;
- }
- if (c > 0) {
- value[count] = c*v;
- size[count++] = c*s;
- }
- }
- 現在用count 代替 n 就和01 揹包問題完全一樣了
下面是利用上面的講解,對HDOJ 2191進行解答,程式碼如下:
- #include <iostream>
- using namespace std;
- int main()
- {
- int nCase,Limit,nKind,i,j,k,
- v[111],w[111],c[111],dp[111];
- //v[]存價值,w[]存尺寸,c[]存件數
- //在本題中,價值是米的重量,尺寸是米的價格
- int count,Value[1111],size[1111];
- //count儲存分解完後的物品總數
- //Value儲存分解完後每件物品的價值
- //size儲存分解完後每件物品的尺寸
- cin>>nCase;
- while(nCase--)
- {
- count=0;
- cin>>Limit>>nKind;
- for(i=0;i<nKind;i++)
- {
- cin>>w[i]>>v[i]>>c[i];
- //對該種類的c[i]件物品進行二進位制分解
- for(j=1;j<=c[i];j<<=1)
- {
- //<<右移1位,相當於乘2
- Value[count]=j*v[i];
- size[count++]=j*w[i];
- c[i] -= j;
- }
- if(c[i] > 0)
- {
- Value[count]=c[i]*v[i];
- size[count++]=c[i]*w[i];
- }
- }
- //經過上面對每一種物品的分解,
- //現在Value[]存的就是分解後的物品價值
- //size[]存的就是分解後的物品尺寸
- //count就相當於原來的n
- //下面就直接用01揹包演算法來解
- memset(dp,0,sizeof(dp));
- for(i=0;i<count;i++)
- for(j=Limit;j>=size[i];j--)
- if(dp[j] < dp[j-size[i]] + Value[i])
- dp[j]=dp[j-size[i]]+Value[i];
- cout<<dp[Limit]<<endl;
- }
- return 0;
- }
在揹包九講裡面,他的實現方法和這個是不一樣的,他是利用01揹包和完全揹包來配合實現的,下面是那個版本的實現
- /*
- HDOJ 2191
- 多重揹包用二進位制轉化的思想,進行優化
- */
- #include <iostream>
- using namespace std;
- int weight[110],Value[110],num[110];
- int f[1100];
- int limit;
- inline void ZeroOnePack(int w,int v)
- {
- int j;
- for(j=limit;j>=w;j--)
- {
- if(f[j-w]+v > f[j])
- f[j]=f[j-w]+v;
- }
- }
- inline void CompletePack(int w,int v)
- {
- int j;
- for(j=w;j<=limit;j++)
- {
- if(f[j-w]+v > f[j])
- f[j]=f[j-w]+v;
- }
- }
- inline void MultiplePack(int w,int v,int amount)
- {
- if(amount * w >= limit)
- {
- CompletePack(w,v);
- return ;
- }
- for(int k=1;k<amount;k<<=1)
- {
- ZeroOnePack(k*w,k*v);
- amount -= k;
- }
- ZeroOnePack(amount*w,amount*v);
- }
- int main()
- {
- int T,n;
- cin>>T;
- while(T--)
- {
- cin>>limit>>n;
- for(int i=0;i<n;i++)
- cin>>weight[i]>>Value[i]>>num[i];
- memset(f,0,sizeof(f));
- for(i=0;i<n;i++)
- MultiplePack(weight[i],Value[i],num[i]);
- cout<<f[limit]<<endl;
- }
- return 0;
- }
相關文章
- poj1276 多重揹包問題(二進位制解決方案)
- 01揹包、完全揹包、多重揹包詳解
- UVA 674 01揹包 2進位制優化 DP優化
- 進位制詳解:二進位制、八進位制和十六進位制
- Mysql二進位制包安裝MySql
- javascript演算法基礎之01揹包,完全揹包,多重揹包實現JavaScript演算法
- 二進位制與二進位制運算
- JavaScript 二進位制、八進位制與十六進位制JavaScript
- 使用二進位制包來安裝MySQLMySql
- Go 釋出二進位制包的方法Go
- 【Redis】原始碼編譯二進位制包Redis原始碼編譯
- 【BZOJ 5003】與鏈 (多重揹包 dp)
- (二進位制)
- 二進位制
- 十進位制——二 (八、十六 )進位制
- 二進位制,八進位制,十進位制,十六進位制的相互轉換
- 【進位制轉換】二進位制、十六進位制、十進位制、八進位制對應關係
- 03二進位制包安裝與介紹
- 二進位制、十進位制與十六進位制相互轉化
- java中二進位制、八進位制、十進位制、十六進位制的轉換Java
- 二進位制,八進位制,十進位制,十六進位制之間的轉換
- Python 進位制互相轉換(二進位制、十進位制和十六進位制)Python
- 計算機基礎進位制轉換(二進位制、八進位制、十進位制、十六進位制)計算機
- 二進位制轉十進位制快速方法
- JAVA 二進位制,八進位制,十六進位制,十進位制間進行相互轉換Java
- 什麼是二進位制?二進位制如何轉換?
- 演算法--揹包九講(詳細講解+程式碼)演算法
- 04 二進位制
- mysql二進位制日誌詳解MySql
- 大話二進位制,八進位制,十進位制,十六進位制之間的轉換
- iOS二進位制和資源包的自檢iOS
- JavaScript十進位制轉換為二進位制JavaScript
- Oracle二進位制與十進位制轉換Oracle
- 十進位制轉二進位制推導(草稿)
- [計算機基礎] 計算機進位制轉換:二進位制、八進位制、十進位制、十六進位制計算機
- 一看就懂二進位制、八進位制、十六進位制數轉換十進位制
- python進位制轉換(二進位制、十進位制和十六進位制)及注意事項Python
- Oracle中的二進位制、八進位制、十進位制、十六進位制相互轉換函式Oracle函式