0/1揹包經典例題 入門動態規劃

  筆者參加美團在線筆試的時候,遇到了一道動態規劃的相關題目,很遺憾當時的筆者很是稚嫩,對算法簡直一竅不通,因而抱着求學的態度,打算入門動態規劃的時候,發現了這個經典的動態規劃(Dynamic Programming,DP)入門題--0/1揹包問題,看完大神們的解答思路,簡直頂禮膜拜,因而打算本身手動實現下,致敬大佬們。特此,摘記。算法

  所謂的0/1表示的就是裝入揹包的物品只有兩種狀態(裝入與不裝入)。   OK,廢話很少說,上題:數組

題目:

條件:
* 一個揹包,最大容量12Kg
* 5個物品,分別的重量爲1 , 3 , 2 , 6 , 2(單位都是Kg),分別的價值爲2 , 5 , 3 , 10 , 4(這個單位任意)
問題:
* 求揹包最多能裝下多少價值的物品?

  OK,談下解題思路:函數

  1. 確認子問題和狀態   01揹包問題須要求解的就是,爲了體積V的揹包中物體總價值最大化,N件物品中第i件應該放入揹包中嗎?(其中每一個物品最多隻能放一件)   爲此,咱們定義一個二維數組,其中每一個元素表明一個狀態,即前i個物體中若干個放入體積爲V揹包中最大價值。數組爲:f[N][V],其中fij表示前i件中若干個物品放入體積爲j的揹包中的最大價值。
  2. 初始狀態   初始狀態爲f[0][0−V]和f[0−N][0]都爲0,前者表示前0個物品(也就是空物品)不管裝入多大的包中總價值都爲0,後者表示體積爲0的揹包啥價值的物品都裝不進去。
  3. 轉移函數
if (揹包體積j小於物品i的體積)
    f[i][j] = f[i-1][j] //揹包裝不下第i個物體,目前只能靠前i-1個物體裝包
else
    f[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi)

  最後一句的意思就是根據「爲了體積V的揹包中物體總價值最大化,N件物品中第i件應該放入揹包中嗎?」轉化而來的。Vi表示第i件物體的體積,Wi表示第i件物品的價值。這樣f[i-1][j]表明的就是不將這件物品放入揹包,而f[i-1][j-Vi] + Wi則是表明將第i件放入揹包以後的總價值,比較二者的價值,得出最大的價值存入如今的揹包之中。code

OK,上筆者本身擼的代碼:orm

package package_0_1;

/**
 * 0/1 揹包問題
 * @author xiao
 *
 */
public class Package01 { 
	// 揹包的最大重量
	public static int package_weight_max = 12;
	// 一共有幾種物品
	public static int Total_Item = 5;
	// 每種物品的價值
	public static int[] values= {0 , 2 , 5 , 3 , 10 , 4};
	// 每種物品的重量
	public static int[] Items_Weight = {0 , 1 , 3 , 2 , 6 , 2};
	/* 一個二維數組,用來表示從前i個物品裏
	 * 選出最合適的裝進載重量爲j揹包中,使
	 * 得揹包裏的價值最大。i∈Items j∈{0-package_weight_max}
	 * dp[i][j] 單位是 (價值)
	*/
	public static int dp[][] = new int[Total_Item+1][package_weight_max+1];
	
	/**
	 * 初始化dp二維數組
	 */
	public static void initialize_dp() {
		for(int[] i : dp) {
			for(int j :i) {
				j=0;
			}
		}
	}
	
	/**
	 * DP 計算遞推矩陣(求出每一個局部最優解,將其保存進二維數組,方便遞推)
	 */
	public static int DPMethod() {
		initialize_dp();
		
		// 構造二維數組
		for(int i = 1;i<=Total_Item;i++) {
			for(int j = 1;j<=package_weight_max;j++) {
				/* 若是揹包容量小於物品的重量,則不放入此物品,
				 * 將放入上一物品的最大價值做爲此次的最大價值
				 */
				if(j<Items_Weight[i]) {
					dp[i][j] = dp[i-1][j];
				}
				/* 若是揹包容量足夠放下這件物品,那麼就
				 * 比較不放入物品時的最大價值與放入此物
				 * 品時的最大價值誰大,將大的做爲此次的最大價值
				 */
				else {
					// GetMax(不放入物品的價值,此物品的價值+剩餘空間的最大價值)
					dp[i][j] = GetMax(dp[i-1][j],(dp[i-1][j-Items_Weight[i]]+values[i]));
				}
				System.out.print(dp[i][j]+" ");
			}
			System.out.println("");
		}
		// 至此求得解
		return dp[Total_Item][package_weight_max];
	}
	
	/**
	 * 求最大值
	 * @param i
	 * @param j
	 * @return
	 */
	private static int GetMax(int i, int j) {
		// TODO Auto-generated method stub
		if(i>j) {
			return i;
		}else {
			return j;
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("計算矩陣以下: ");
		int result = DPMethod();
		System.out.println(String.format("12kg揹包最多能裝進價值爲 %d 的物品", result));
	}

}

OK,先記錄到這!it

相關文章
相關標籤/搜索