多重揹包,二進位制優化,單調佇列優化

2021-05-27 13:51:42 字數 2664 閱讀 7106

採藥

【問題描述】

辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說:「孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡,你可以採到一些草藥。如果你是乙個聰明的孩子,你應該可以讓採到的草藥的總價值最大。」 如果你是辰辰,你能完成這個任務嗎?

【輸入檔案】

輸入檔案medic.in的第一行包含兩個正整數n,m。m表示總共能夠用來採藥的時間,n代表山洞裡的草藥的數目。接下來的n行每行包括兩個的整數,分別表示採摘某株草藥的時間ti和這株草藥的價值vi。

【輸出檔案】

輸出檔案為medic.out,僅包含乙個整數表示規定時間內可以採到的草藥的最大總價值。

【輸入樣例】

3 910 10

8 11 2

【輸出樣例】

3【資料規模和約定】

50%的資料中 n,m ≤ 1000;

100%的資料中 n,m ≤ 100000,ti,vi ≤10。

若有n種物品,揹包容量為m,物品體積、價值、最大使用次數為v,w,c,則樸素的動規方程為:f[i]=max (1<=k<=c)。我們把所有可能達到的體積按照除以當前物品體積v的餘數劃分為0~v-1,則當餘數為k(k∈[0,v-1])時又可以劃分為k,k+v,k+2*v…k+j*v…(1<=j<=(m-k)div v)這幾種具體的體積,由於對於餘數為k時的轉移只會發生在以上列舉出的幾個體積上,所以可以建立關於以上幾個體積的單調佇列,以便於快速地找到最優決策。但是這裡要注意一點,由於這幾個決策的體積和價值都不相同,直接沒有可比性,所以我們把這些決策的體積統一到為k時比較,統一方法只需要利用體積為k+j*v這一特點,把需要插入隊中的f[k+j*v]的價值減去j*w,就是當體積為k時的乙個可以用於比較的「參考」價值。可以很容易想到:由於轉移時,使用當前物品貢獻的那一部分是二者之差,所以這與減掉j*w之前是等效的。

這樣,每次求f[k+j*v]時,只需要在佇列中找到乙個最優的決策f[k+j』*v],使得j-j』<=c即可,剩下的工作就只有維護單調佇列了。

核心**和注釋:

procedure insert(x,y:longint);//插入到乙個價值單調遞減,使用次數單調遞增的佇列中

begin

while (l<=r)and(b[r]<=y) do dec(r);

inc(r);a[r]:=x;b[r]:=y;

end;

begin

readln(n,m);  //n為物品個數、m為揹包容量

for i:=1 to n do

begin

read(v,w,c);  //讀入當前物品:v為物品體積、w為物品價值、c為物品可用次數

if m div v最多可使用次數

for k:=0 to v-1 do  //把所有的體積按除以v的餘數劃分為0~v-1

begin

l:=1;r:=0;  //清空佇列

for j:=0 to (m-k) div v do  //餘數為k的又分為k,v+k,2*v+k…j*v+k…

begin

insert(j,f[j*v+k]-j*w);  //等效於把體積統一到k,價值減去j*w,這樣比較優劣才有意義

while a[l]刪除次數超過c的

f[j*v+k]:=b[l]+j*w;      //用佇列頭的值更新f[j*v+k]

end;

end;

end;

writeln(f[m]);

end.

/*

多重揹包問題:第一種為二進位制優化 時間複雜度 o(nmlog2s)

第二種使用單調佇列 時間複雜度 o(nm)

*/ //方法一

#include #define max(a,b) (a)>(b)?(a):(b)

int dp[100001];

int w[11][11];

int main()

for(int i = 1; i < 11; ++i)//多重揹包

for(int v = m; v >= count*i; --v)

dp[v] = max(dp[v],dp[v-count*i]+count*j);

}else//完全揹包

}} int ans = 0;

for(int i = 0; i <= m; ++i)

if( ans < dp[i]) ans = dp[i];

printf("%d\n",ans);

return 0;

}/* 方法2

#include #define max(a,b) (a)>(b)?(a):(b)

int f[100001];

int ww[11][11];

int l,r;

int a[100001];

int b[100001];

inline void insert(int x,int y)

int main()

for(int i = 1; i < 11; ++i)

for(int jj = 1; jj < 11; ++jj)}}

printf("%d\n",f[m]);

return 0;

}*/

多重揹包二進位制優化

多重揹包二進位制優化 將價值數量相同的物品分成1,2,4,8.因為100以內任何數都可以由幾個2的n次方數組成。所以,有遍歷沒乙個數變為遍歷每乙個2的n次方數。例題 有n種物品,每種物品的數量為c1,c2.cn。從中任選若干件放在容量為w的揹包裡,每種物品的體積為w1,w2.wn wi為整數 與之相...

多重揹包(二進位制優化)

馬上就要輕院校賽了,沒時間了,下面是網上找的多重揹包,感覺很好 void zeroonepack int cost,int weight,int n void completepack int cost,int weight,int n void multipack int c,int w,int ...

多重揹包二進位制優化

時間長不寫 感覺變菜了。整體優化思路和快速冪很相近 如果第i個物品有num i 個,花費是 c i 價值是 v i 那麼我們可以把它拆分成數個物品。比如某個物品數量是14 花費是cost 價值是value 1 2 4 7 就可以把14個相同物品看成 4 個不同的物品,物品 數量花費 價值第乙個 11...