動態規劃之01揹包問題(最易理解的講解)

rebirth_love發表於2016-09-13

轉載地址:http://blog.csdn.net/mu399/article/details/7722810

01揹包問題,是用來介紹動態規劃演算法最經典的例子,網上關於01揹包問題的講解也很多,我寫這篇文章力爭做到用最簡單的方式,最少的公式把01揹包問題講解透徹。

01揹包的狀態轉換方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] }

f[i,j]表示在前i件物品中選擇若干件放在承重為 j 的揹包中,可以取得的最大價值。
Pi表示第i件物品的價值。
決策:為了揹包中物品總價值最大化,第 i件物品應該放入揹包中嗎 ?

題目描述:

有編號分別為a,b,c,d,e的五件物品,它們的重量分別是2,2,6,5,4,它們的價值分別是6,3,5,4,6,現在給你個承重為10的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?

name weight value 1 2 3 4 5 6 7 8 9 10
a 2 6 0 6 6 9 9 12 12 15 15 15
b 2 3 0 3 3 6 6 9 9 9 10 11
c 6 5 0 0 0 6 6 6 6 6 10 11
d 5 4 0 0 0 6 6 6 6 6 10 10
e 4 6 0 0 0 6 6 6 6 6 6 6

只要你能通過找規律手工填寫出上面這張表就算理解了01揹包的動態規劃演算法。

首先要明確這張表是至底向上,從左到右生成的。

為了敘述方便,用e2單元格表示e行2列的單元格,這個單元格的意義是用來表示只有物品e時,有個承重為2的揹包,那麼這個揹包的最大價值是0,因為e物品的重量是4,揹包裝不了。

對於d2單元格,表示只有物品e,d時,承重為2的揹包,所能裝入的最大價值,仍然是0,因為物品e,d都不是這個揹包能裝的。

同理,c2=0,b2=3,a2=6。

對於承重為8的揹包,a8=15,是怎麼得出的呢?

根據01揹包的狀態轉換方程,需要考察兩個值,

一個是f[i-1,j],對於這個例子來說就是b8的值9,另一個是f[i-1,j-Wi]+Pi;

在這裡,

 f[i-1,j]表示我有一個承重為8的揹包,當只有物品b,c,d,e四件可選時,這個揹包能裝入的最大價值

f[i-1,j-Wi]表示我有一個承重為6的揹包(等於當前揹包承重減去物品a的重量),當只有物品b,c,d,e四件可選時,這個揹包能裝入的最大價值

f[i-1,j-Wi]就是指單元格b6,值為9,Pi指的是a物品的價值,即6

由於f[i-1,j-Wi]+Pi = 9 + 6 = 15 大於f[i-1,j] = 9,所以物品a應該放入承重為8的揹包

以下是java的程式碼view plain copy

import java.util.Arrays;

public class Package01 {
	public static void main(String[] args) {
		int wholeWeight = 10;
		PackageItem[] packageItems = init();
		int[][] result = get01PackageAnswer(packageItems, wholeWeight);
		for (int i = 0; i < result.length; i++) {
			System.out.println(Arrays.toString(result[i]));
		}
	}
	
	private static int[][] get01PackageAnswer(PackageItem[] packageItems, int wholeWeight) {
		int[][] matrix = new int[packageItems.length][wholeWeight + 1];//二位陣列
		for (int i = 0; i < packageItems.length; i++) {//行
			PackageItem pi = packageItems[i];//要放進包的item
			int piWeight = pi.weight;
			int piValue = pi.value;
			
			for (int j = 1; j <= wholeWeight; j++) {//列
				int bagSize = j;//當前揹包的能承受的重量
				if (piWeight > bagSize) {//裝不了
					//matrix[i][j] = matrix[i][j - 1];
					
					if (i ==0) {//如果是第0行
						matrix[i][j] = 0;
					} else {
						matrix[i][j] = matrix[i - 1][j];
					}
				} else {
					int weightDiff = bagSize - piWeight;//裝入當前item,餘下的重量
					if (i ==0) {//如果是第0行
						matrix[i][j] = piValue;
					} else {
						int valueInBag = matrix[i - 1][weightDiff] + piValue;//f[i-1,j-Wi]+Pi(j >= Wi)
						matrix[i][j] = valueInBag > matrix[i - 1][j] ? valueInBag : matrix[i - 1][j];
					}
				}
			}
		}
		return matrix;
	}
	
	static PackageItem[] init() {
		String[] nameArr = {"a","b","c","d","e"};
		int[] weightArr = {2,2,6,5,4};
		int[] valueArr = {6,3,5,4,6};
		PackageItem[] packageItems = new PackageItem[nameArr.length];
		for (int i = 0; i < nameArr.length; i++) {
			PackageItem pi = new PackageItem(nameArr[i], weightArr[i], valueArr[i]);
			packageItems[i] = pi;
		}
		return packageItems;
	}
}
class PackageItem  
{  
    public String name;  
    public int weight;  
    public int value;  
    public PackageItem(String name, int weight, int value)  
    {  
        this.name = name;
        this.weight = weight;
        this.value = value;
    }  
}  


相關文章