在多重揹包的直接拆分法中,個數為$c[i]$的物體被拆成$c[i]$種不同的物體
這樣就使得物體的種類增加了很多,使得演算法效率很低。
上述方法把$c[i]$拆成$c[i]$個1,於是任意選擇可以表示出$1$到$c[i]$之間的所有數,從而達到多重揹包的目的
想到,從$2^0,2^1,2^2,...,2^k$任意選擇可以表示出$1$到$2^-1$之間的所有數
於是就有了二進位制拆分法:
首先找到最大的$k$,使得$\sum_^2^i<=c[i]$
令$t=\sum_^2^i$,易知,上面$k+1$個數可以組成$1$到$t$之間的任何數
那$t+1$到$c[i]$之間的數怎麼表示呢?
令$p=c[i]-t$,再拆出乙個p,就可以了,理由如下:
$c[i]=p+t,c[i]-1=p+t-1...$依次類推
由於$1$到$t$已經被表示,所以這樣一來$1$到$c[i]$之間的每個整數都可以被表示
具體來說,就是把數量為$c[i]$的物體分為$k+2$個,它們的體積分別為$2^0*v[i],2^1*v[i],...,2^k*v[i],p$
code:
是$poj1742coins$的**,雖然會tle,就當打了個二進位制拆分法的板子叭
1 #include2 #include3 #include4view code#define ri register int
5#define il inline
6#define mem(a,b) memset(a,b,sizeof(a))
7#define go(i,a,b) for(ri i=a;i<=b;i++)
8#define yes(i,a,b) for(ri i=a;i>=b;i--)
9using
namespace
std;
10const
int n=101,m=100001;11
intn,m,t,p,ans,a[n],c[n];
12bool
f[m];
13 il void calc(int
x)14
17 t=x-t/3;p--;18}
19int
main()
2036 yes(k,m,t)f[k]|=f[k-t];37}
38 go(i,1,m)if(f[i])ans++;
39 printf("
%d\n
",ans);40}
41return0;
42 }
多重揹包(二進位制拆分優化)
多重揹包基本模型如下 給定n種物品,其中第i種物品的體積為vi,價值為wi,並且有ci個。有一容積為m的揹包,要求選擇若干個物品放入揹包,使得物品總體積不超過m的前提下,物品價值總和最大。輸入格式 第一行兩個整數,n,m,用空格隔開,分別表示物品種數和揹包容積。接下來有 n 行,每行三個整數 vi,...
POJ1014 多重揹包(二進位制拆分)
題目鏈結 題目大意 給出6個數,分別代表價值為1 6的6種物品的數量,求能否在價值相同的情況下平分這些物品。思路 多重揹包。一開始拆成01揹包來做,寫了三層迴圈,很顯然結果tle了。後來上網看了一下題解,大致意思是把每一種物品的數量拆成1,2,4,8,這樣的2的n次方數,比如將12拆成1,2,4,5...
東東與 ATM 多重揹包 二進位制拆分
題意 一家銀行計畫安裝一台用於提取現金的機器。機器能夠按要求的現金量傳送適當的賬單。機器使用正好n種不同的面額鈔票,例如d k,k 1,2,n,並且對於每種面額d k,機器都有n k張鈔票。例如,n 3,n 1 10,d 1 100,n 2 4,d 2 50,n 3 5,d 3 10 表示機器有10...