動態規劃 揹包問題 比值問題轉揹包問題

2021-06-25 22:35:28 字數 2784 閱讀 2838

動態規劃--dynamic programming

可以用動態規劃解決的問題都可以通過直接遞迴來解決,但這樣的時間複雜度通常都會高達指數關係。所以,通過以空間換時間的代價,用dp通常可以達到o(n*m)的時間複雜度,至於空間複雜度,就要看問題的要求了:

1)如果要求得到整個dp過程中的細節,如揹包問題中的放了哪些物品、lcs問題中的lcs的值,那麼就要o(n*m)的空間複雜度;

2)如果只需要知道最後的結果,如揹包問題中所放物品的最大價值、lcs問題中的lcs的長度,那麼就只需要o(n)的空間複雜度。

當然,如果只需要直接輸出存入了的物品,那麼o(n)的空間複雜度也是可以的。

下面先討論0-1揹包問題(不要求正好放滿,要求輸出放了哪些物品)的實現:

//動態規劃求解

int zeroonepack(int total_weight, int w, int v, int flag, int n) else

else

}} }

//下面求解哪個物品應該放進揹包

int i = n, j = total_weight;

while (c[i][j] != 0) --i;

} int val=c[n][total_weight];

//釋放二維陣列

for(int i=0;i

接下來,分析只要求輸出能放下的物品的最**值的0-1揹包問題,因為c[i][j]的結果只依賴於c[i-1][j]和才c[i-1][j-w[i-1]],所以,只要知道前一行的資料,就能求出接下來一行的資料。至於當前行的資料的儲存問題,如果從行尾開始計算的話,直接用當前行c[i][j]代替前一行的資料c[i-1][j]就能解決,所以,儲存已經計算過的前i個物品放入容量為1,2,...,total_weight的揹包的最大值這些資料只需要taotal_weight+1(加上c[0]=0)的空間。

0-1揹包問題(不要求正好放滿,只要求輸出能放下的物品的最**值)

的實現:

int zero_one_pack(int total_weight, int w, int v, int n)  else 

} }

} int val=c[total_weight];

delete c;

return val;

}int _tmain(int argc, _tchar* argv)

;//物品重量

int v[4] = ;//物品價值

int total_value = zero_one_pack(total_weight, w, v, 4);

cout << "總的價值為: " << total_value << endl;

system("pause");

return 0;

}

對於0-1揹包問題,如果要求正好裝滿的話,就要對上面的**做些改動,只要在初始化陣列c的時候稍加改動就行。初始化的時候,將c[0]/c[i][0]初始化為0,其他都初始化為負無窮大。這樣,對於c[j]c[j-w[i]]>0,如果放不進,c[j-w[i]]必然是負無窮大,因為負無窮大加有限值依然是負無窮大

),那麼前i個物品必然能正好放入容量為j的揹包中。這時c[j]c[j]將被賦值為v[i]+c[j-w[i]]。當然在程式中不能真的將變數賦值為負無窮大,不過可以用很小的值代替,如32系統上用const int min=0x80000000代替。這樣,如果c[weight]>0,表明揹包能正好被裝滿,且裝入物品的價值為c[weight]。

對於0-1揹包問題,如果要求正好裝滿的**如下:

const int min=0x80000000;

//動態規劃求解

int zeroonepack(int total_weight, int w, int v, int flag, int n) else

else

}} }

//下面求解哪個物品應該放進揹包

int i = n, j = total_weight;

while (c[i][j] > 0) --i;

} int val=c[n][total_weight];//如果val>0則能正好裝滿,否則無解

//釋放二維陣列

for(int i=0;i題意:有1,5,10,25,50這五種硬幣。給乙個價值,求有多少種組合可以得到該價值。

完全揹包:因為每個物品都能放多次,所以第二層迴圈從小到大的的順序。

首先想到了用dp[j][0]代表容量為j的揹包能裝下的最大價值,dp[j][1]代表容量為j的揹包裝下最大價值時的組合方式數量。

一定要注意:揹包問題的外層迴圈是物品種類0,1,2...,n-1,內層迴圈是揹包容量v[i],...,weight。在確定轉移方程的時候最好腦海裡能回憶書上那個**~

const int m = 2000;

int _tmain(int argc, _tchar* argv)

; int weight;

int n=5;

while(cin)

//情況二:前i-1個物品放入容量為j中的價值能達到前i個物品放入容量為j中的價值

//那麼,前i個物品放入容量為j中的方式=前i-1個物品放入容量為j中的方式(不放第i個)+放第i個時的方式

//其中,放第i個時的方式數量等於前i個物品放入容量為j-v[i]的方式數量(其實這點是幣值問題中最巧妙的)

else if(dp[j-v[i]][0]+v[i] == dp[j][0])

}} cout<

對於一定要恰好裝滿的情況,比如沒有面值為2的硬幣,這時要怎麼改還沒想清楚。

動態規劃揹包問題 01揹包

問題描述 n種物品,每種乙個。第i種物品的體積為vi,重量為wi。選一些物品裝到容量為c的揹包,使得揹包內物品不超過c的前提下,重量最大。問題分析 宣告乙個f n c 的陣列。f i j 表示把前i件物品都裝到容量為j的揹包所獲得的最大重量。當 j v i 時,揹包容量不足以放下第 i 件物品,f ...

動態規劃揹包問題 完全揹包

問題描述 有n種物品,每種均有無窮多個。第i個物品的體積為vi,重量為wi。選一些物品裝到容量為c的揹包中,使得揹包內物品在總體積不超過c的前提下重量盡量大。問題分析 開乙個陣列f i j 表示前i種物品中選取若干件物品放入剩餘空間為j的揹包中所能得到的最大重量。每種物品無窮個,所以還要有乙個k遍歷...

動態規劃 揹包問題 01揹包

有n種物品和乙個容量為v的揹包,每種物品僅用一次。第i件物品的費用是w i 價值是v i 求解將哪些物品裝入揹包可使價值總和最大。例如 n 5,v 10 重量 價值 第乙個物品 10 5 第二個物品 1 4 第三個物品 2 3 第四個物品 3 2 第五個物品 4 1 首先我們考慮貪心策略,選取最大價...