多重揹包:有n種物品,每個物品的重量為w[i],每個物品的價值為h[i],每種物品有c[i]個。
最樸素的做法中,我們把c[i]個物品i看成c[i]個不同的物品,進而轉化成了0-1揹包。然後在0-1揹包的基礎上我們還可以進行二進位制優化
我們知道:
20,21,22,23,,,2n可以組成1~2(n+1)-1中的任意數(每個數只能用一次)
所以我們可以把c[i]個相同的物品,看成這樣的幾堆物品:
10=1+2+4+3
15=1+2+4+8
36=1+2+4+8+16+5
後面的4、4、6(olog(n))堆物品就可以代替前面的10、15、36(o(n))堆,因為他們可以組成1~c[i]的任意數,複雜度也就在這裡降低了
for
(int i=
1; i<=n; i++)if
(c[i]
)for
(int j=v; j>=c[i]
*w[i]
; j--
) dp[j]
=max
(dp[j]
,dp[j-c[i]
*w[i]
]+c[i]
*h[i]);
}
0-1揹包中我們為了保證每件物品只參與了一次,在第二層迴圈中我們是從後往前遍歷for(j=v; j>=w[i]; j–)。但在完全揹包中,每件物品都可以用無數次,所以直接從前往後遍歷一遍就可以for(j=w[i]; j<=v; j++)。他們的複雜度都是o(n*v)(兩層迴圈)
多重揹包中,每件物品的個數是有限的,在轉化成0-1揹包以及它的二進位制優化中,我們另外加了一層迴圈來限制每件物品的數量。那麼我們如果想將多重揹包轉化為完全揹包,又怎麼保證結果中每件物品使用的數量不會超過c[i]呢?————我們可以用乙個陣列cou來記錄當前物品使用的次數。當我們發現當前物品的使用數量超過c[i]時退出迴圈就可以了。
例題:題意:瑪莎和比爾有一堆彈珠,他們想把彈珠分開,一人乙份。如果彈珠的大小一樣就好了,那樣直接一人一半。不幸的是,這些彈珠大小不一。所以他們倆就給每個彈珠編了乙個號,從1到6,現在他們想把這些彈珠分成兩份,只要他們最後得到的總值一樣就可以。然而問題又來了,因為他們發現如果彈珠是1、3、4、4這種情況,他們任然無法平分。所以現在他們想讓你確定一下他們這堆彈珠是否能夠被平分。
**:
#include
#include
#include
typedef
long
long ll;
const
int maxn=
1e4+
100;
int a1,b,c,d,e,f,k=
1,dp[
101000
],cou[
100010];
intmain()
memset
(dp,0,
sizeof
(dp));
dp[0]
=1;for
(int i=
1; i<=
6; i++)if
(dp[sum/2]
)break;}
}if(dp[sum/2]
)printf
("collection #%d:\ncan be divided.\n\n"
,k++);
else
printf
("collection #%d:\ncan't be divided.\n\n"
,k++);
}return0;
}
其他例題:coins 多重揹包二進位制優化
多重揹包二進位制優化 將價值數量相同的物品分成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...