1. 程式人生 > >揹包問題九講02-完全揹包問題總結

揹包問題九講02-完全揹包問題總結

1.題目描述:

假設有n件物品,每件物品都有value,和cost屬性,現有一個容量為v的揹包,現在每件物品都有無限件可以選擇,請問為了使揹包的總價值最大,我們該怎麼挑選放入揹包的物品,輸出我們的最大總價值

2.思路:

不同於01揹包問題的完全揹包問題,和01揹包問題有所不同,完全揹包問題強調了,每種物品都有無限件可以選取,那麼我們最終要檢查的狀態就不在是01揹包問題中的O(V*N)而是擴充套件成O(V*SUM(V/cost[i]))件物品,顯然因為擴充套件了可能選擇的情況,我們的時間複雜度激素飆升,在揹包容量非常大,並且物品的耗費很小的時候,這種演算法的時間複雜度有些顯得力不從心 但是我們還是來寫一下還方法的狀態和狀態專業方程,位我們接下來的優化提供契機 定義狀態:
dp[i][j]:在揹包容量為j的情況下,我們在放入前i件物品的時候(最大選擇上線是V/cost[i])可以獲得的最大價值
狀態轉移方程:
dp[i][j]=max(dp[i][j-k*cost[i]]+k*value[i])  //K從0~V/cost[i](選擇下界)

3.簡單優化:

1.思路上的優化:

我們不好理解哇暖揹包問題的話,其實不妨把完全揹包問題轉化成01揹包問題,我們這樣來看待我們的完全揹包,既然每一個物品都有V/cost[i]中選擇方式,那麼我們就不妨從01揹包的思路入手,我們將物品機體擴充,每件物品都有V/cost[i]件,那麼我們就將問題裝化成了有n*sum(V/cost[i])件物品的01揹包問題了,但是這種想法上的優化對於我們優化時間複雜度沒有任何實際上的作用,我們需要掃描的狀態的數目仍然是O(V*n*sum(V/cost[i])
)中狀態,但是,這種事路其實給我們提供了一種01揹包和完全揹包之間的聯絡

2.01揹包思路的進一步優化:

我們可以發現,每一件物品既然都要拆成n*sum(V/cost[i])件物品,我們是選擇每件物品單獨來作為一種情況來進行組裝,但是我們仔細想想就會發現,實際上,我們為了找過所有的情況,沒有必要拆除那麼多的物品,想一下二進位制的原理,任何一個數我們都可以由二進位制數目進行組合來得到,那我們同樣的,如果我們將每個物品最多拆成二進位制個話,我們完全就可以實現我們需要的所有的狀態了 比如,為了實現表示我們二進位制的100(4),我們沒必要拆出4個狀態:1,10,11,100,我們只需要2^k=4,k=2種狀態就可以了,也就是說,我們最多隻需要1和10就能夠高速的實現我們的所有的狀態的組合 這樣的話,我們來回到正題上,對於完全揹包的話,我們每個物品只需要cost[i]*2^k<=V,也就是說log(V/cost[i])個狀態就好了 那麼我們01揹包需要的掃描的狀態數目就是 O(V*n*log(V/cost[i])) 我們現在來比較一下兩個狀態:
O(V*n*log(V/cost[i]))
O(V*n*V/cost[i])
顯而易見,我們在01揹包的思路之上,成功的優化了我們的時間複雜度 PS:這裡我們選擇了2^k來拆,其實根據個人喜好3^k,4^k都是可以的,但是在計算時間複雜度的時候我們統一是用2^k來作為標準的

3.O(V*N)優化思路:

其實我們的O(V*N)的思路其實很好得到,但是這裡面我們的額優化思路和我們的01揹包的思路是不一樣的,我們還是從前往後掃,一會我來解釋一下這一點的額含義是什麼 先上核心程式碼:
for(int i=1;i<=n;i++)
{
	for(int j=0;j<=v;j++)  //可以黑箱優化 
	{
		dp[i][j]=max(dp[i][j],dp[i][j-cost[i]]+value[i]);
	}
} 
PS:所謂的常數優化,就是我們每次起點都是cost[I],在我們的物品的cost比較高的時候,該優化的效果是很可觀的 我們這樣優化的思路其實很簡單 首先,我們這樣優化是建立在內層迴圈是從前往後進行的,每一次,我們之前的狀態都是已經計算過的 那麼我們再來考慮我們原先的沒有優化的時候的狀態
dp[i][j]=max(dp[i][j-k*cost[i]]+k*value[i])  //K從0~V/cost[i](選擇下界)
在這裡我們發現,我們的k次優化是不斷遞增的,也就是說我們下一次的k可以通過k-1已經計算出來的值(這個計算出來的值已經是前一段的k是最優的),我們直接拿這個最優解和我們的當前的解進行比較就可以了

4.空間複雜度的優化:

我們其實沒必要開闢那麼多的,我們只需要之前計算的數值和當前位置的資料(當前的資料是一個都不取) 黑箱優化:
void absolutepackage(int cost,int value)
{
	for(int i=cost;i<=v;i++) dp[i]=max(dp[i],dp[i-cost]+value);
}

void test()
{
	for(int i=1;i<=n;i++) absolutepackage(cost[i],value[i]);
}