1. 程式人生 > >演算法基礎-動態規劃 (1) 01揹包問題

演算法基礎-動態規劃 (1) 01揹包問題

最近閒的無聊,演算法一直是弱項,正好hihocoder上面開始了每週的比賽,

這周的題目是01揹包問題。正好歸納和總結一下。

所有的動態規劃問題都兩個特點:

1、重複子問題一個問題可以轉化成幾個同類型的子問題。

2、後無關性:前一個問題產生的決策和結果,對下一個問題沒有影響。

說白了,就是你能吧問題寫成簡單的數學遞迴表示式:

對於01揹包問題,建模很關鍵,

這裡面有幾個關鍵量 

物品個數N

能容納的重量M

每個物品的價值V(i)

每個物品的重量w(i)

我們要想好這個數學表示式

對於每個物品而言,有兩種狀態,被選上和不被選上, 即0和1狀態。而對整個揹包而言  能夠承受的重量就是裡面物品的加和,同樣價值一樣也是加和。

我們希望揹包儘可能裝得多,而且產生的價值最大,(最重要的的是總價值最高)

所以整個表示式應該以價值作為衡量因素。

下面是表示式:


N個物品,揹包有M重量空餘,等於在前N-1選擇最大的,一種是不選擇第N-1個物品,另一種是選擇第N-1個物品,並佔據了揹包Wn的重量,但提供了Vn的價值。

下面是三種程式碼形式,孰優孰劣,大家一眼就能開出來。

	public int getcurrentVlue(int i,int j){
		if(i==0){
			if(j>=0) return 0;
		}
		if(j<0) return Integer.MIN_VALUE;		
		return max (getcurrentVlue(i-1, j),getcurrentVlue(i-1, j-w[i-1])+v[i-1]);
	}


	public int getvalue(int sum,int wei){
		int[] [] value =new int [sum][wei];
		for(int i=1;i<sum;i++){
			for(int j=0;j<wei;j++){
				if(j<w[i-1]) value[i][j] = value[i-1][j];
				else{
					value[i][j] = max (value[i-1][j],value[i-1][j-w[i-1]]+v[i-1]);
				}
			}
		}
		return wei;
	}

public int getvalues(int sum, int wei) {
		int[] value = new int[wei + 1];
		for (int i = 1; i < sum + 1; i++) {
			for (int j = wei; j > w[i - 1] - 1; j--) {
				value[j] = value[j] > value[j - w[i - 1]] + v[i - 1] ? value[j]
						: value[j - w[i - 1]] + v[i - 1];
			}
		}
		return value[wei];
	}


顯然第三種效果最好。