Codevs 3269 混合揹包

2022-04-10 00:08:34 字數 3378 閱讀 2370

題目描述 description

揹包體積為v ,給出n個物品,每個物品占用體積為vi,價值為wi,每個物品要麼至多取1件,要麼至多取mi件(mi>1) , 要麼數量無限 , 在所裝物品總體積不超過v的前提下所裝物品的價值的和的最大值是多少?

輸入描述 input description

第一行兩個數n,v,下面n行每行三個數vi,wi,mi表示每個物品的體積,價值與數量,mi=1表示至多取一件,mi>1表示至多取mi件,mi=-1表示數量無限

輸出描述 output description

1個數ans表示所裝物品價值的最大值

樣例輸入 sample input

2 10

3 7 2

2 4 -1

樣例輸出 sample output

22資料範圍及提示 data size & hint

對於100%的資料,v <= 200000 , n <= 200

題目說的很民白了。。。。

這道題就是01揹包,完全揹包,多重揹包的結合,而且資料極大。【資料大得pascal呼叫max函式還會tle!!調(kan)了(le)好(ti)久(jie)才發現這個問題

倘若是01揹包與完全揹包的結合,這道題就挺好辦的,就可以這樣亂搞:

for i:=1

to n do

begin

if01揹包的情況 then

for j:=m downto w[i] do f[j]:=max(f[j],f[j-w[i]]+c[i]) else

if 完全揹包的情況 then

for j:=w[i] to m do f[j]:=max(f[j],f[j-w[i]]+c[i]) ;

end;

01+完全

可事實不是這樣的,還多了乙個多重揹包。接下來就來說明一下怎麼將多重揹包轉成01揹包。

假定我們讀入的第i個物品的數量為p[i],重量w[i],價值c[i],那麼p[i]個物品就可以分為數量分別為1,2,4,...,2^log2p[i]的物品,不夠分直接取剩餘的。

比如說,當p[i]=8,w[i]=3,c[i]=5時,可以分為如下4個物品:

1.p[1]=1; w[1]=w[i]*p[1]=3*1=3; c[1]=c[i]*p[1]=5*1=5

2.p[2]=2; w[2]=w[i]*p[2]=3*2=6; c[2]=c[i]*p[2]=5*2=10

3.p[3]=4; w[3]=w[i]*p[3]=3*4=12; c[1]=c[i]*p[3]=5*4=20

4.p[4]=1; w[4]=w[i]*p[4]=3*1=3; c[4]=c[i]*p[1]=5*1=5

這樣分有什麼好處呢?

如果我們不這麼做,那麼要將它轉化為01揹包就必須將p[i]分成p[i]份,每份一件物品,以滿足p[i]+1種取的方法(即取0個,取1個,...,取p[i]個),這樣子的最終的效率為o(m*sigma(p[i]))【m為揹包容量】,不用看,效率極低。

我們將p[i]分為log2p[i]份則恰好解決的這個問題,先看效率,縮至o(m*sigma(log2p[i])),接著不難發現,所分成的這log2p[i]個數恰好可以拼成0..p[i]之間任意乙個數,如上面p[i]=8的例子,取0件則一件不取,取1件則取p[1]或p[4],取2件則取p[1]+p[4]或p[2],取3件則取p[1]+p[2]或p[4]+p[2],取4件則取p[1]+p[2]+p[4]或p[3],取5件則取p[1]+p[3]或p[4]+p[3],取6件,取7件,取8件我就懶得打了。。

於是將它轉化為01揹包後就可以套用上面的**了。

程式:

1

var w1,w,c1,c,p1,p:array[0..10000] of

int64;

2var f:array[0..200000] of

int64;

3var

top,k,n,m:int64;

4var

i,j:longint;

5function pow(x:longint):int64;//沒事敲快速冪練手感

6begin

7if x=0

then exit(1

);8 pow:=pow(x >> 1

);9 pow:=pow*pow;

10if odd(x) then pow:=pow*2;11

end;

12begin

13readln(n,m);

14for i:=1

to n do

readln(w[i],c[i],p[i]);

15for i:=1

to n do

16begin

17if (p[i]=-1)or(p[i]=1) then//01

揹包或完全揹包的情況

18begin

19 inc(top);w1[top]:=w[i];c1[top]:=c[i];p1[top]:=p[i];

20continue;

21end;22

for j:=0

to trunc(ln(p[i])/ln(2))+1

do//處理多重揹包的情況

23begin

24if p[i]=0

then

break;

25 k:=pow(j);

26if p[i]>=k then

27begin

28 p[i]:=p[i]-k;inc(top);w1[top]:=w[i]*k;c1[top]:=c[i]*k;p1[top]:=k;

29end

else

30if p[i]then//處理剩餘的情況

31begin

32 k:=p[i];

33 inc(top);w1[top]:=w[i]*k;c1[top]:=c[i]*k;p1[top]:=k;

34break;

35end;36

end;

37end;38

for i:=1

to top do//亂搞

39begin

40if p1[i]=-1

then

for j:=w1[i] to m do

begin

if f[j]then f[j]:=f[j-w1[i]]+c1[i]; end

else

41if p1[i]>0

then

for j:=m downto w1[i] do

begin

if f[j]then f[j]:=f[j-w1[i]]+c1[i]; end;42

end;

43writeln(f[m]);

44end.

codevs 3269-混合揹包

codevs 3269 混合揹包

題目描述 description 揹包體積為v 給出n個物品,每個物品占用體積為vi,價值為wi,每個物品要麼至多取1件,要麼至多取mi件 mi 1 要麼數量無限 在所裝物品總體積不超過v的前提下所裝物品的價值的和的最大值是多少?輸入描述 input description 第一行兩個數n,v,下面...

codevs 3269 混合揹包

題目描述 description 揹包體積為v,給出n個物品,每個物品占用體積為vi,價值為wi,每個物品要麼至多取1件,要麼至多取mi件 mi 1 要麼數量無限 在所裝物品總體積不超過v的前提下所裝物品的價值的和的最大值是多少?輸入描述 input description 第一行兩個數n,v,下面...

Codevs 3269 混合揹包

時間限制 1 s 空間限制 256000 kb 題目等級 鑽石 diamond description 揹包體積為v 給出n個物品,每個物品占用體積為vi,價值為wi,每個物品要麼至多取1件,要麼至多取mi件 mi 1 要麼數量無限 在所裝物品總體積不超過v的前提下所裝物品的價值的和的最大值是多少?...