數據結構與算法 -- 動態規劃算法

一、0-1揹包問題算法

//0-1揹包問題--動態規劃算法
public class DynamicPlan {

    public static void main(String[] args) {
        DynamicPlan dynamicplan = new DynamicPlan();
        int[] weight = {1, 2, 3, 4, 5};
        System.out.println("方法一     揹包所裝物品的重量爲:" + dynamicplan.knapsack(weight, weight.length, 12));
        System.out.println("方法二     揹包所裝物品的重量爲:" + dynamicplan.knapsack2(weight, weight.length, 12));
    }

    //方法一      weight:物品重量,n:物品個數,w:揹包可承載重量
    public int knapsack(int[] weight, int n, int w) {
        boolean[][] states = new boolean[n][w+1];//默認值false
        states[0][0] = true;//第一行的數據要特殊處理,能夠利用哨兵優化
        if(weight[0] <= w) {
            states[0][weight[0]] = true;
        }
        for(int i=1; i<n; i++) {//動態規劃狀態轉移
            for(int j=0; j<=w; j++) {//不把第i個物品放入揹包
                if(states[i-1][j] == true) {
                    states[i][j] = states[i-1][j];
                }
            }
            for(int j=0; j<=w-weight[i]; j++) {//把第i個物品放入揹包
                if(states[i-1][j] == true) {
                    states[i][j+weight[i]] = true;
                }
            }
        }
        for(int i=w; i>=0; i--) {//輸出結果
            if(states[n-1][i] == true) {
                return i;
            }
        }
        return 0;
    }
    
    //方法二      weight:物品重量,n:物品個數,w:揹包可承載重量
    public int knapsack2(int[] weight, int n, int w) {
        boolean[] states = new boolean[w+1];//默認值false
        states[0] = true;//第一行的數據要特殊處理,能夠利用哨兵優化
        if(weight[0] <= w) {
            states[weight[0]] = true;
        }
        for(int i=1; i<n; i++) {//動態規劃狀態轉移
            for(int j=w-weight[i]; j>=0; j--) {//把第i個物品放入揹包
                if(states[j] == true) {
                    states[j+weight[i]] = true;
                }
            }
        }
        for(int i=w; i>=0; i--) {//輸出結果
            if(states[i] == true) {
                return i;
            }
        }
        return 0;
    }
}

 二、0-1揹包問題【升級版】數組

//0-1揹包問題【升級版】--動態規劃算法
public class DynamicPlan {

    public static void main(String[] args) {
        DynamicPlan dynamicplan = new DynamicPlan();
        int[] weight = {2, 2, 4, 6, 3};//物品的重量
        int[] value = {3, 4, 8, 9, 6};//物品的價值
        int n = 5;//物品個數
        int w = 9;//揹包承受的最大重量
        System.out.println("揹包所裝物品的最大價值爲:" + dynamicplan.knapsack3(weight, value, n, w));
    }

    //方法一      weight:物品重量,n:物品個數,w:揹包可承載重量
    public int knapsack3(int[] weight, int[] value, int n, int w) {
        int[][] states = new int[n][w+1];
        for(int i=0; i<n; i++) {//初始化states
            for(int j=0; j<w+1; j++) {
                states[i][j] = -1;
            }
        }
        states[0][0] = 0;
        if(weight[0] <= w) {
            states[0][weight[0]] = value[0];
        }
        for(int i=1; i<n; i++) {//動態規劃狀態轉移
            for(int j=0; j<=w; j++) {//不把第i個物品放入揹包
                if(states[i-1][j] >= 0) {
                    states[i][j] = states[i-1][j];
                }
            }
            for(int j=0; j<=w-weight[i]; j++) {//把第i個物品放入揹包
                if(states[i-1][j] >= 0) {
                    int v = states[i-1][j] + value[i];
                    if(v > states[i][j+weight[i]]) {
                        states[i][j+weight[i]] = v;
                    }
                }
            }
        }
        //找出最大值
        int maxValue = -1;
        for(int j=0; j<=w; j++) {
            if(states[n-1][j] > maxValue) {
                maxValue = states[n-1][j];
            }
        }
        return maxValue;
    }
}

三、"雙十一"購物拼單問題優化

/**
 * "雙十一"購物拼單問題--動態規劃算法
 * 
 * "雙十一"購物節舉辦一個"滿200元減50元"的促銷活動,假設你女友的購物車中有
 * n(n>100)個想買的商品,她但願從裏面選幾個,在湊夠滿減條件的前提下,讓選出來
 * 的商品價格和最大程度的接近滿減條件(200元),這樣就能夠極大限度的"薅羊毛"
 */
public class DynamicPlan {

    public static void main(String[] args) {
        DynamicPlan dynamicplan = new DynamicPlan();
        int[] items = {12, 25, 48, 6, 33, 120, 59, 88, 4, 71, 169, 23, 112};
        dynamicplan.double11advance(items, items.length, 200);
    }
    
    //items 商品價格,n 商品個數,w 表示滿減條件,好比200
    public void double11advance(int[] items, int n, int w) {
        boolean[][] states = new boolean[n][3*w+1];//超過3倍就沒有薅羊毛的價值了
        states[0][0] = true;//第一行的數據要特殊處理
        if(items[0] <= 3*w) {
            states[0][items[0]] = true;
        }
        for(int i=1; i<n; i++) {//動態規劃
            for(int j=0; j<=3*w; j++) {//不購買第i個商品
                if(states[i-1][j] == true) {
                    states[i][j] = states[i-1][j];
                }
            }
            for(int j=0; j<=3*w-items[i]; j++) {//購買第i個商品
                if(states[i-1][j] == true) {
                    states[i][j+items[i]] = true;
                }
            }
        }
        
        int j;
        for(j=w; j<3*w+1; j++) {
            if(states[n-1][j] == true) {
                break;//輸出結果大於等於w的最小值
            }
        }
        if(j == 3*w+1) {
            return;//沒有可行解
        }
        for(int i=n-1; i>=1; i--) {//i表示二維數組中的行,j表示列
            if(j-items[i] >= 0 && states[i-1][j-items[i]] == true) {
                System.out.print(items[i] + " ");//購買這個商品
                j = j - items[i];
            }//else 沒有購買這個商品,j不變
        }
        if(j != 0) {
            System.out.print(items[0]);
        }
    }
}
相關文章
相關標籤/搜索