多重揹包的 二進位制優化 轉化為有限制的完全揹包

2021-09-25 05:53:34 字數 1861 閱讀 8663

多重揹包:有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...