關於帶限制條件的二維裝箱-------重量價值雙重限制下,使得價值最大

在做題的時候,遇到一個 二維揹包問題,需要在重量不超過重量限制的情況下,使價值接近價值限制,但不能超過它。經過嘗試後發現,對G矩陣進行一些處理可以得出結果。

首先是從value[] 中選出一個不超過,但最接近valueLimit的值,記錄它的位置,然後去G矩陣裏從這個位置開始倒推,可以得到想要的解,即物品的位置。代碼如下:

iimport java.util.Arrays;
import java.util.Scanner;

public class Knapsack {
    private final static int MIN = Integer.MIN_VALUE;
    public static void main(String[] args){
    	int wLimit = 8;
    	int vLimit = 13;
    	int[] w = {1,2,2,4,6};
        int[] v = {2,3,5,6,7};
        knapsackOptimal(wLimit, w,vLimit, v);
    }
    /**
     * @param weightLimit  總重量限制    
     * @param weight 物品重量
     * @param valueLimit   總價值限制
     * @param value  物品價值
     * 在總重量,和總價值不超出限制條件下,使得價值最大化
     */
    public static void knapsackOptimal(int weightLimit, int[] weight, int valueLimit,int[] value) {
        int n = weight.length; 
        int[] w = new int[n + 1];
        int[] v = new int[n + 1];
        //G[i][j]表示前i個物品能裝入容量爲j的揹包中的最大價值
        int[][] G = new int[n + 1][weightLimit + 1];
        for (int i = 1; i < n + 1; i++) {
            w[i] = weight[i - 1];
            v[i] = value[i - 1];
        }
        //初始化values[0...c]=0————在不超過揹包容量的情況下,最多能獲得多少價值
        //原因:如果揹包並非必須被裝滿,那麼任何容量的揹包都有一個合法解“什麼都不裝”,這個解的價值爲0,所以初始時狀態的值也就全部爲0了
        int[] values = new int[weightLimit + 1];
        //初始化values[0]=0,其它全爲負無窮————解決在恰好裝滿揹包的情況下,最多能獲得多少價值的問題
        //原因:只有容量爲0的揹包可以什麼物品都不裝就能裝滿,此時價值爲0,其它容量揹包均無合法的解,屬於未定義的狀態,應該被賦值爲負無窮
        /*for (int i = 1; i < values.length; i++) {
            values[i] = MIN;
        }*/
        for (int i = 1; i < n + 1; i++) {
            for (int t = weightLimit; t >= w[i]; t--) {
                if ( (values[t] < values[t - w[i]] + v[i] ) ) {
                	 values[t] = values[t - w[i]] + v[i];
                     G[i][t] = 1;
                }
            }      
        }
        System.out.println("價值矩陣:"+Arrays.toString(values));
        System.out.println("無價值限制下的最大價值:" + values[weightLimit]);
        System.out.println("G矩陣: ");
        for(int i=0;i<G.length;i++){
        	System.out.println(Arrays.toString(G[i]));
        }
        
        int index = getValueIndex(values,valueLimit);
        
        System.out.println("滿足價值限制條件下的最大價值:"+values[index]);
        System.out.println("index"+index);     
        /*
                    輸出順序:逆序輸出物品編號
      	注意:這裏另外開闢數組G[i][v],標記上一個狀態的位置
        G[i][v] = 1:表示物品i放入揹包了,上一狀態爲G[i - 1][v - w[i]]
  		G[i][v] = 0:表示物品i沒有放入揹包,上一狀態爲G[i - 1][v]
        */
        System.out.println("輸出物品位置: ");
        int i = n;
//        int j = weightLimit;//無限制下計算位置,從最後一列開始倒推
        int j = index;//有限制下計算物品位置,從該行開始倒推
        while (i > 0) {
            if (G[i][j] == 1) {
                System.out.print(i + " ");
                j -= w[i];
            }
            i--;
        }
    }
    //Finds the position of the value in the largest value array ( value[] )that 
    //is less than and closest to valueLimit .
	private static int getValueIndex(int[] values,int valueLimit) {
		int index = 0;
		// TODO Auto-generated method stub
		if(valueLimit-values[values.length-1]>0){
        	index = values.length-1;
        }else{
        	for(int i=0;i<values.length;i++){
    	     	if(valueLimit-values[i]<0){
    	     		index = i-1;
    	     		break;	     		
    	     	}if(valueLimit-values[i]==0){
    	     		index = i;
    	     		break;	
    	     	}	    	     	
    	    }
        }
		return index;
	}
}

樣例運行結果

價值矩陣:[0, 2, 5, 7, 8, 10, 11, 13, 14]
無價值限制下的最大價值:14
G矩陣: 
[0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 1, 1, 1, 1, 1, 1, 1]
[0, 0, 0, 0, 0, 0, 1, 1, 1]
[0, 0, 0, 0, 0, 0, 0, 0, 0]
滿足價值限制條件下的最大價值:13
index7
輸出物品位置: 
4 3 1 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章