動態規劃 01揹包問題

2021-08-19 13:16:20 字數 3044 閱讀 6894

問題描述:給定 n 種物品和乙個容量為 c 的揹包,物品 i 的重量是 wi,其價值為 vi 。

:應該如何選擇裝入揹包的物品,使得裝入揹包中的物品的總價值最大?

題目分析:從n種物品中選擇m種商品放入容量為c的揹包,v1+v2+v3+……+vm最大,即求最優解,這裡我們使用動態規劃來解決該問題。題目需要求解揹包容量為c時的最優解,那麼我們可以分解問題,讓揹包容量從1增加到c,依次求解容量為1時的最優解、容量為2時的最優解;那麼基於動態規劃求最優解的性質——將子問題的最優解集合之後就是總問題的最優解,我們即可求得揹包問題的最優解。

動態規劃:動態規劃與分治法類似,都是把大問題拆分成小問題,通過尋找大問題與小問題的遞推關係,解決乙個個小問題,最終達到解決原問題的效果。但不同的是,分治法在子問題和子子問題等上被重複計算了很多次,而動態規劃則具有記憶性,通過填寫表把所有已經解決的子問題答案紀錄下來,在新問題裡需要用到的子問題可以直接提取,避免了重複計算,從而節約了時間,所以在問題滿足最優性原理之後,用動態規劃解決問題的核心就在於填表,表填寫完畢,最優解也就找到。

實現思路:宣告乙個陣列table[n+1][c+1],table[i][j]表示在揹包容量為 j 、選擇第 i 件商品的時候所能獲得商品的最大價值。現在我們需要實現乙個函式 inittable(int value, int weight, int n, int capacity),該函式用來初始化這個table,value[i]陣列表示第 i 個商品的價值(i 從1開始計算),weight[i]  表示第 i 個商品的權值,即所佔揹包的容量。

面對乙個商品,我們有裝入揹包和不裝入揹包兩種選擇,那麼我們來分析一下table[i][j] 的計算方法。

(1) j < w[i] 的情況,這時候揹包容量不足以放下第 i 件物品,只能選擇不拿:m[ i ][ j ] = m[ i-1 ][ j ]

(2) j >= w[i] 的情況,這時揹包容量可以放下第 i 件物品,我們就要考慮拿這件物品是否能獲取更大的價值。

拿:table[i ][j]  = table[ i-1 ][ j - weight[i] ] + value[ i ]

不拿:table[i ][j] = table[ i - 1 ][ j ]

我們需要比較兩種情況下的table[i ][j]值,做出相應選擇。

現在我們寫出實現**:

/**

* 初始化table,table右下角的值即為最優解

* @param value 價值陣列

* @param weight 權值陣列

* @param n 商品種類

* @param capacity 揹包容量

* @return table

*/private static int inittable(int value, int weight, int n, int capacity)

int table = new int[n + 1][capacity + 1];

for(int i = 1; i <= n; i++) else else }}

} return table;

}

這樣就可以得到最優解了,最優解是table[n] [ capacity ]。可是,我們還想獲得選擇了哪幾種商品,這又該怎麼實現呢?這裡我們知道了最優解,那麼我們可以使用逆向思維來思考一下, 最優解是 table[ i ] [ j ] ,那麼table[ i ] [ j ] = table[ i -1 ] [ j ] 或者 table[ i - 1 ] [ j  -  weight [i] ] + value[i], 我們可以根據初始化table的思路來進行求解:

1) table[ i ][ j ] = table[ i -1 ] [ j ] 時,說明沒有選擇第i 個商品,則回到v(i-1,j);

2)table[ i ][ j ] = table[ i - 1 ] [ j  -  weight [i] ] + value[i]

時,說明裝了第i個商品,該商品是最優解組成的一部分,隨後我們得回到裝該商品之前,即回到v(i-1,j-w(i));

3) 一直遍歷到 i  < 0結束為止,所有解的組成都會找到。

**如下:

/**

* 通過回溯獲得選擇的商品:根據最優解回溯找出解的組成

* @param i

* @param j

* @param table 資訊記錄表

* @param weight 權值陣列

* @param value 價值陣列

* @param result 返回結果陣列

*/private static void findchoice(int i, int j, int table, int weight, int value, int result) else if(table[i][j] == (table[i-1][j-weight[i]] + value[i]))

} }

main函式測試如下:

public static void main(string args) 

value = new int[n+1];

weight = new int[n+1];

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

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

int table = inittable(value, weight, n, capacity);

system.out.println("最優解:" + table[n][capacity]);

int choice = new int[n+1];

findchoice(n, capacity, table, weight, value, choice);

system.out.println("選擇商品陣列,1表示選擇,0表示沒有選擇:" + arrays.tostring(choice));

sc.close();

}

動態規劃揹包問題 01揹包

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

動態規劃 揹包問題 01揹包

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

0 1揹包問題(動態規劃)

一 問題描述 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。所謂01揹包,表示每乙個物品只有乙個,要麼裝入,要麼不裝入。二 解決方案 考慮使用動態規劃求解,定義乙個遞迴式 opt i v 表示前i個物品,在揹包容量大小為v的情況下,最...