經典動態規劃--01揹包問題

揹包問題具體例子:假設現有容量10kg的揹包,另外有3個物品,分別爲a1,a2,a3。物品a1重量爲3kg,價值爲4;物品a2重量爲4kg,價值爲5;物品a3重量爲5kg,價值爲6。將哪些物品放入揹包可以使得揹包中的總價值最大?算法

首先想到的,通常是窮舉法,一個一個地試,對於數目小的例子適用,若是容量增大,物品增多,這種方法就無用武之地了。編程

  其次,能夠先把價值最大的物體放入,這已是貪婪算法的雛形了。若是不添加某些特定條件,結果未必可行。數組

  最後,就是動態規劃的思路了。先將原始問題通常化,欲求揹包可以得到的總價值,即欲求前i個物體放入容量爲m(kg)揹包的最大價值ci——使用一個數組來存儲最大價值,當m取10,i取3時,即原始問題了。而前i個物體放入容量爲m(kg)的揹包,又能夠轉化成前(i-1)個物體放入揹包的問題。下面使用數學表達式描述它們二者之間的具體關係。spa

  表達式中各個符號的具體含義。.net

  w[i] : 第i個物體的重量;code

  p[i] : 第i個物體的價值;blog

  ci : 前i個物體放入容量爲m的揹包的最大價值;圖片

  ci-1 : 前i-1個物體放入容量爲m的揹包的最大價值;ci

  ci-1] : 前i-1個物體放入容量爲m-w[i]的揹包的最大價值;get

  由此可得:

      ci=max{ci-1]+pi , ci-1}(下圖將給出更具體的解釋)
圖片描述
  根據上式,對物體個數及揹包重量進行遞推,列出一個表格(見下表),表格來自(http://blog.csdn.net/fg2006/a...) ,當逐步推出表中每一個值的大小,那個最大價值就求出來了。推導過程當中,注意一點,最好逐行而非逐列開始推導,先從編號爲1的那一行,推出全部c1的值,再推編號爲2的那行c2的大小。這樣便於理解。
圖片描述
  思路釐清後,開始編程序,Java代碼以下所示:

public class BackPack {
    public static void main(String[] args) {
        int m = 10;
        int n = 3;
        int w[] = {3, 4, 5};
        int p[] = {4, 5, 6};
        int c[][] = BackPack_Solution(m, n, w, p);
        for (int i = 1; i <=n; i++) {
            for (int j = 1; j <=m; j++) {
                System.out.print(c[i][j]+"\t");
                if(j==m){
                    System.out.println();
                }
            }
        }
        //printPack(c, w, m, n);

    }

 /**
     * @param m 表示揹包的最大容量
     * @param n 表示商品個數
     * @param w 表示商品重量數組
     * @param p 表示商品價值數組
     */
    public static int[][] BackPack_Solution(int m, int n, int[] w, int[] p) {
        //c[i][v]表示前i件物品恰放入一個重量爲m的揹包能夠得到的最大價值
        int c[][] = new int[n + 1][m + 1];
        for (int i = 0; i < n + 1; i++)
            c[i][0] = 0;
        for (int j = 0; j < m + 1; j++)
            c[0][j] = 0;

        for (int i = 1; i < n + 1; i++) {
            for (int j = 1; j < m + 1; j++) {
                //當物品爲i件重量爲j時,若是第i件的重量(w[i-1])小於重量j時,c[i][j]爲下列兩種狀況之一:
                //(1)物品i不放入揹包中,因此c[i][j]爲c[i-1][j]的值
                //(2)物品i放入揹包中,則揹包剩餘重量爲j-w[i-1],因此c[i][j]爲c[i-1][j-w[i-1]]的值加上當前物品i的價值
                if (w[i - 1] <= j) {
                    if (c[i - 1][j] < (c[i - 1][j - w[i - 1]] + p[i - 1]))
                        c[i][j] = c[i - 1][j - w[i - 1]] + p[i - 1];
                    else
                        c[i][j] = c[i - 1][j];
                } else
                    c[i][j] = c[i - 1][j];
            }
        }
        return c;
    }

運行結果爲:

0 0 4 4 4 4 4 4 4 4
0 0 4 5 5 5 9 9 9 9
0 0 4 5 6 6 9 10 11 11

Process finished with exit code 0

相關文章
相關標籤/搜索