01揹包問題Java(動態規劃和暴力求解)

比較經典的一個問題,在理清思路之後,寫出了代碼。動態規劃的思想還是將大的問題分解成小的的問題。或者說是分成小的步驟。例如在揹包問題中,想求解揹包容量爲N的最大價值,先求解容量爲N-1的最大價值,一步一步向前推,最終在返回來。自己也是理解了好久,突然有一天早上刷牙,就把問題想明白了。還是要多悟,多說無益,看代碼:

package com.zxg.algorithm.PackageQuestion;

/**
 * 01揹包問題 將重量爲(w1,w2,w3,w4,w5...)、價值爲(v1,v2,v3,v4,v5...)的物品放入容量爲N的揹包中,怎樣放價值最大
 * 動態規劃:
 * 我們設v[i][j]爲放入前i個物品到容量爲j的揹包中的最大值,i一定是小於物品總個數的,j一定是小於N的
 * 舉個例子 v[2][5]表示將前兩個物品放入容量爲5的揹包中的最大價值 v[2][6]表示將前兩個物品放入容量爲6的揹包中的最大價值
 * 則有等式:
 * v[0][j] = v[j][0] = 0
 * v[i][j] = v[i-1][j] w[i]>j
 * v[i][j] = Max(v[i-1][j],v[i-1][j-w[i]]+value[i]) w[i] <= j
 * 暴力求解:
 * 求出物品個數的所有子集,計算每一個子集的價值,選出最大值
 * 例如有4個物品,那麼2^4=16個子集,每個子集有四位,每一位是0代表該子集中沒有該物品,是1代表有該物品
 * 0 0 0 0 代表該子集中沒有任何物品
 * 0 1 0 1 代表該子集中有2號物品和4號物品
 */
public class Package_01 {

    /**
     * 動態規劃
     * @param weight
     * @param value
     * @param capacity
     * @return
     */
    public static int maxValue(int[] weight, int[] value, int capacity) {
        int weightLen = weight.length;
        int valueLen = capacity + 1;//列值長度加1,是因爲最後一列要保證重量值爲lenColumn
        int maxValue = 0;
        int[][] v = new int[weightLen][valueLen];
        for (int i = 0; i < weightLen; i++) {
            for (int j = 0; j < valueLen; j++) {
                if (i == 0) {
                    v[i][j] = 0;
                } else if (j == 0) {
                    v[i][j] = 0;
                } else {
                    if (weight[i] > j) {
                        v[i][j] = v[i - 1][j];

                    } else if (weight[i] <= j) {
                        v[i][j] = Math.max(v[i - 1][j], v[i - 1][j - weight[i]] + value[i]);
                    }
                    maxValue = v[i][j];
                }

            }

        }
        return maxValue;
    }

    /**
     * 暴力求解
     * @param weight
     * @param value
     * @param capacity
     * @return
     */
    public static int maxValueForce(int[] weight,int[] value,int capacity){
        //子集個數
        int row = (int)Math.pow(2,weight.length);
        //每個子集中元素個數,就是物品的個數
        int column = weight.length;
        //物品子集
        int[][] goodsSubset = new int[row][column];
        //最大價值
        int maxValue = 0;
        //填充所有子集
        for(int i=0;i<row;i++){
            int temp_1 = i;
            for(int j=0;j<column;j++){
                int temp_2 = temp_1%2;
                goodsSubset[i][j] = temp_2;
                temp_1 = temp_1/2;
            }
        }
        //遍歷子集,爲每一個子集計算總價值,輸出總價值最大的子集
        for(int i=0;i<goodsSubset.length;i++){
            int tempWeight = 0;
            int tempValue = 0;
            for(int j=0;j<goodsSubset[i].length;j++){
                System.out.printf(goodsSubset[i][j]+" ");
                tempWeight += goodsSubset[i][j]*weight[j];
                tempValue += goodsSubset[i][j]*value[j];
            }
            System.out.print("\t"+"總重量爲:"+ tempWeight);
            if(tempWeight <= capacity){
                System.out.printf("\t"+"總價值爲:"+tempValue);
            }else {
                System.out.printf("\t"+"不可行,超出揹包最大承重");
            }
            if(tempWeight <= capacity && tempValue>maxValue){
                maxValue = tempValue;
            }
            System.out.println();
        }
        System.out.println("最大值:"+maxValue);
        return maxValue;
    }

    public static void main(String[] args) {
//        int[] weight = {1, 3, 5, 7, 1};
//        int[] value = {2, 4, 3, 6, 3};
        int[] weight = {7,3,4,5};
        int[] value = {42,12,40,25};
        int capacity = 10; //容量
        System.out.println(maxValue(weight, value, capacity));
    }

}

參考:https://www.cnblogs.com/liuzhen1995/p/6374541.html#a2.3

           https://blog.csdn.net/ls5718/article/details/52227908

           https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html     

這裏再多說一句,爲什麼不能使用貪心算法思路來解決,因爲使用貪心算法的前提是無後效性,即某個狀態以後的過程不會影響以前的狀態,只與當前狀態有關。但是放在該問題中不適用,因爲你在當前選擇了一個物品,就增加了揹包相應的重量,那麼剩餘的重量就會減少,這對之後再選擇物品時時有影響的。 所以對所採用的貪心策略一定要仔細分析其是否滿足無後效性。

 

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