解題報告 The Bags

2022-06-04 02:24:10 字數 3146 閱讀 9294

lynn 和banana要去爬山啦!他們一共有 k 個人(banana的人數可以看作很多),每個人都會背乙個包。這些包的容量是相同的,都是 v。可以裝進揹包裡的一共有 n 種物品,每種物品都有給定的體積和價值。在 lynn看來,合理的揹包安排方案是這樣的:

(1)每個人揹包裡裝的物品的總體積恰等於包的容量。 

(2)每個包裡的每種物品最多只有一件,但兩個不同的包中可以存在相同的物品。 

(3)任意兩個人,他們包裡的物品清單不能完全相同。 

在滿足以上要求的前提下,所有包裡的所有物品的總價值最大是多少呢?

【輸入格式】

第一行有三個整數:k、v、n。(k<=50 v<=5000 n<=200)第二行開始的 n 行,每行有兩個整數,分別代表這件物品的體積和價值。

【輸出格式】

只需輸出乙個整數,即在滿足以上要求的前提下所有物品的總價值的最大值。(最後有空行.)

【樣例輸入】

2 10 5

3 12

7 20

2 45 6

1 1【樣例輸出】

5701 揹包前 

k 優解的模型。

本人動規好菜的,所以,解析**自揹包九講。。。。。。。我貌似有把這篇文章放在 blog 

上,貌似還置頂著呢。。。。。

求次優解、第k優解

對於求次優解、第k

優解類的問題,如果相應的最優解問題能寫出狀態轉移方程、用動態規劃解決,那麼求次優解往往可以相同的複雜度解決,第k

優解則比求最優解的複雜度上多乙個係數k。

其基本思想是將每個狀態都表示成有序佇列,將狀態轉移方程中的max/min

轉化成有序佇列的合併。這裡仍然以

01揹包為例講解一下。

首先看01

揹包求最優解的狀態轉移方程:

f[i][v]=max

。如果要求第

k優解,那麼狀態

f[i][v]

就應該是乙個大小為

k的陣列

f[i][v][1..k]

。其中f[i][v][k]表示前i

個物品、揹包大小為

v時,第k

優解的值。「f[i][v]

是乙個大小為

k的陣列

」這一句,熟悉

c語言的同學可能比較好理解,或者也可以簡單地理解為在原來的方程中加了一維。顯然

f[i][v][1..k]這k

個數是由大到小排列的,所以我們把它認為是乙個有序佇列。

然後原方程就可以解釋為:f[i][v]

這個有序佇列是由

f[i-1][v]

和f[i-1][v-c[i]]+w[i]

這兩個有序佇列合併得到的。有序佇列

f[i-1][v]

即f[i-1][v][1..k]

,f[i-1][v-c[i]]+w[i]

則理解為在

f[i-1][v-c[i]][1..k]

的每個數上加上

w[i]

後得到的有序佇列。合併這兩個有序佇列並將結果(的前

k項)儲存到

f[i][v][1..k]

中的複雜度是

o(k)

。最後的答案是

f[n][v][k]

。總的複雜度是

o(nvk)

。為什麼這個方法正確呢?實際上,乙個正確的狀態轉移方程的求解過程遍歷了所有可用的策略,也就覆蓋了問題的所有方案。只不過由於是求最優解,所以其它在任何乙個策略上達不到最優的方案都被忽略了。如果把每個狀態表示成乙個大小為k

的陣列,並在這個陣列中有序的儲存該狀態可取到的前

k個最優值。那麼,對於任兩個狀態的

max運算等價於兩個由大到小的有序佇列的合併。

另外還要注意題目對於「第k

優解」的定義,將策略不同但權值相同的兩個方案是看作同乙個解還是不同的解。如果是前者,則維護有序佇列時要保證佇列裡的數沒有重複的。

varcost,value:array[1..200] of longint;

f:array[0..5000,0..200] of longint;

maxv,ans,m,i,j,k,n,p1,p2:longint;

temp1,temp2:array[1..500] of longint;

begin

assign(input,'bags.in');

assign(output,'bags.out');

reset(input);

rewrite(output);

readln(m,maxv,n);

for i:=1 to n do

readln(cost[i],value[i]);

for i:=0 to maxv do

for j:=1 to m do

f[i,j]:=-maxlongint; 

f[0,1]:=0;

for i:=1 to n do

begin

for j:=maxv downto cost[i] do  //正著更新是每個物品使用無限次,可能會反覆著加好幾遍,倒著更新是每個物品使用一次

begin

p1:=1; p2:=1;

for k:=1 to m do

begin

temp1[k]:=f[j,k];

temp2[k]:=f[j-cost[i],k]+value[i];

end;

for k:=1 to m do

if temp1[p1]>=temp2[p2] then

begin

f[j,k]:=temp1[p1];

inc(p1);

endelse

begin

f[j,k]:=temp2[p2];

inc(p2);

end;  //從 

temp1 

,temp2 

中找出前 

k 大的(方法,歸併排序,因為 

temp 

本來就是有序的,所以不用過多處理)更新第 

k 優值。

end;

end;

for i:=1 to m do

inc(ans,f[maxv,i]);

writeln(ans);

close(input);

close(output);

end.

Block Voting 解題報告

這道題做的有點狼狽,效率不高,差一點就tle的ac了。看status裡的,ac的時間大多數都是0ms的。肯定有乙個更有效率的演算法的。下面說下我的狼狽演算法。出處 http acm.jlu.edu.cn joj showproblem.php?pid 1223 問題描述 求每個party的權值。第i...

Safebreaker 解題報告

又是吉林大學一道acm題目,題目很簡單,直接暴力解決。出處 http acm.jlu.edu.cn joj showproblem.php?pid 1718 問題描述 對乙個給定數0000 9999 根據一系列猜測,判斷這個數是否存在,存在的話,是否唯一 例如 3321,給定數 作出猜測,1223 ...

路由 解題報告

路由 問題描述 有乙個tcp ip網路 每台計算機都有乙個或多個網路介面。每個介面根據它的ip位址和子網掩碼來識別 即兩個4位元組的數,兩個字 節之間有乙個 號.子網掩碼有乙個二進位制表示法 有k個 1 然 後是 m 個 0 k m 8 4 32 如 212.220.35.77 是乙個 ip 地 址...