0-1揹包問題

揹包問題:n種物品,每種物品有重量w和價值v,揹包所能承受的最大重量爲c。如何挑選物品可使總物品的價值最大。java

0-1揹包問題:限定每種物品的個數只能是0或1.算法

如:5個物品,質量分別爲3,5,7,8,9,價值分別爲4,6,7,9,10。揹包所能承受重量爲22.ide

給物品從0開始編號,挑選物品1,3,4(價值分別爲6,9,10)時,總價值最大爲25,此時重量爲22.spa

 

運用動態規劃思想,能夠構造有效的方法。code

 

算法基本思路:blog

1.構造最優表,獲取最大價值;字符串

構造表mv[0...n][0...c],mv[i][j] 表示 前 i 項物品(即0到i-1)中挑選物品放入承受重量爲 j 的最大價值。get

顯然,當 i 爲0即沒有物品時,mv[0][*] = 0;當 j 爲0即最大重量爲0時,mv[*][0] = 0。(*表示任意)input

對於mv[i][j]只有兩種可能的狀況,it

(要注意的是,i 表示前i 項物品,物品編號從0開始,即 i-1 表示第i 項物品)

(1)當w[i-1] > j 即當前物品重量大於當前最大承受重量時,只能放棄當前物品即 mv[i][j] = mv[i-1][j];

(2)當w[i-1] <= j 即當前物品重量小於當前最大承受重量時,經過比較取此物品後的最大價值(即mv[i-1][j-w[i-1]] + v[i-1])與不取此物品的最大價值(即mv[i-1][j]),挑出較大值即 mv[i][j] = max(mv[i-1][j], mv[i-1][j-w[i-1]])。

經過上述自底向上打表,可構造出最優值mv[n][c]。

 

2.經過最優表,獲取構造路線即挑出能夠獲得最大價值的物品。

經過上述可知,當w[i-1] > j 時,mv[i][j] = mv[i-1][j];當w[i-1] <= j 時,mv[i][j] = max(mv[i-1][j], mv[i-1][j - w[i-1]] + v[i-1])。

逆推此過程,從mv[n][c]出發,一直到 i 爲 0(沒有物品)或 j 爲 0(沒有更多重量)。

當w[i-1] > j 時,可知沒有挑選此物品,此時 i - 1;

當w[i-1] <= j 時,再比較 mv[i][j] 是否與 mv[i-1][j] 相等,如果,則沒有挑選此物品,此時 i - 1;若不等,則說明有挑選此物品,此時 i - 1, j - w[i-1]。

 

算法實現:

基本上和上述相似,但須要注意的是,返回結果,我同時返回了最優值和物品編號,涉及一些java處理字符串的小技巧,和此算法無關,能夠忽略。

 

/*
input:     w[0..n-1]            //w[i] = the weight of Object i
        v[0..n-1]            //v[i] = the value of Object i
        c                      //c = the weight of Knapsack

table:    mv[0..n][0..C]        //mv[i][j] = select some objects from O[0..i-1], then satify the max value(weight < weight j)

if i = 0, means no objects, so mv[0][*] = 0
if j = 0, means no weights, so mv[*][0] = 0
else    if w[i-1] > j, means not enough weight, so mv[i][j] = mv[i-1][j]
        if w[i-1] <= j, means enough weight, so mv[i][j] = min(mv[i-1][j], mv[i-1][j-w[i-1]] + v[i-1])
        //note that mv[i-1][j-w[i]] means the best answer of O[0..i-1] in weight j-w[i-1]
        //note that i means ith object, so it is w[i-1] rather than w[i]
*/

import java.util.ArrayList;

public class Knapsack {
    
    public static String getMaxValue(int[] w, int[] v, int c){
        int[][] mv = new int[w.length+1][c+1];
        //i = 0
        for(int j = 0; j <= c; j ++){
            mv[0][j] = 0;
        }
        //j = 0
        for(int i = 0; i <= w.length; i ++){
            mv[i][0] = 0;
        }
        //compute
        for(int i = 1; i < mv.length; i ++){
            for(int j = 1; j <= c; j ++){
                if(w[i-1] > j){
                    mv[i][j] = mv[i-1][j];
                }
                else{
                    mv[i][j] = Math.max(mv[i-1][j], mv[i-1][j-w[i-1]] + v[i-1]);
                }
            }
        }
//        for(int i = 0; i < mv.length; i ++){
//            for(int j = 0; j < mv[0].length ; j ++){
//                System.out.print(mv[i][j] + " ");
//            }
//            System.out.println();
//        }
        //get result
        ArrayList<Integer> index = getObjectsIndex(w, v, c, mv);
        String result = Integer.toString(mv[w.length][c]);
        for(int i = 0; i < index.size(); i ++)
            result += "/" + Integer.toString(index.get(i));
        return result;
    }

    private static ArrayList<Integer> getObjectsIndex(int[] w, int[] v, int c, int[][] mv){
        ArrayList<Integer> index = new ArrayList<Integer>();
        int i = mv.length-1, j = c;
        while(i > 0 && j > 0){
            if(w[i-1] > j){
                i --;
            }
            else{
                if(mv[i-1][j] == mv[i][j]){
                    i --;
                }
                else{
                    index.add(i-1);
                    j -= w[i-1];
                    i --;
                }
            }
        }
        return index;
    }

    public static void main(String[] args) {
        int c = 22;
        int[] w = {3, 5, 7, 8, 9};
        int[] v = {4, 6, 7, 9, 10};
        String[] result = getMaxValue(w, v, c).split("/");
        System.out.println(result[0]);
        for(int i = 1; i < result.length; i ++)
            System.out.print(result[i] + " ");
        System.out.println();
    }

}
Java
相關文章
相關標籤/搜索