動態規劃-01揹包問題

算法思想:動態規劃
實際問題:01揹包問題
編寫語言:Javajava


問題描述

給定n種物品和一個揹包,物品i的重量爲wi,其價值是vi,揹包的容量爲c,問應如何向背包裝入物品,使得揹包中的物品價值最大。每一個物品拿取或者不拿兩種選擇。不能選擇裝入某物品的一部分,也不能裝入同一物品屢次。算法

遞歸結構

聲明一個大小爲m[n][c]的二維數組,m[i][j]表示在面對第i件物品,且揹包容量爲j時所能得到的最大價值。則:數組

  1. m[i][j]=m[i-1][j],j<w[i]。其表示:揹包容量不足以放下第i件物品,只能選擇不拿。
  2. m[i][j]=max{m[i-1][j], m[i-1][j-wi]+vi},j>=w[i]。其表示:這時揹包容量能夠放下第i件物品,咱們就要考慮拿這件物品是否能獲取更大的價值。前者表示不裝第i件物品的最大價值,後者表示裝了第i件物品的最大價值,併爲第i件物品預留了wi的容量。

Java代碼

public class OneZeroKnapsackProblem
{
    public static void main(String[] args)
    {
        //如下數組第0位(第0行,第0列)都不存儲數據
        int[] v = new int[]{0, 8, 10, 6, 3, 7, 2}; //每件物品的價值
        int[] w = new int[]{0, 4, 6, 2, 2, 5, 1}; //每件物品的重量
        int c = 12; //揹包的容量
        int n = v.length - 1; //物品的數量
        int[][] m = new int[n + 1][c + 1]; //總價值數組
        int[] r = new int[n + 1]; //構造最優解的數組
        
        for(int i = 0; i <= n; i++)
        {
            for(int j = 0; j <= c; j++)
                m[i][j] = 0;
            r[i] = 0;
        }
        
        knapsack(v, w, c, n, m);
        traceback(m, w, c, n, r);
        
        System.out.println("物品數量爲 " + n + " ,揹包容量爲 " + c);
        
        System.out.print("各個物品的價值爲:");
        for(int i = 1; i <= n; i++)
        {
            System.out.print(v[i] + " ");
        }
        System.out.println();
        
        System.out.print("各個物品的重量爲:");
        for(int i = 1; i <= n; i++)
        {
            System.out.print(w[i] + " ");
        }
        System.out.println();
        
        System.out.println("最多價值爲:" + m[n][c]);
        
        System.out.print("放入的物品爲:");
        for(int i = 1; i <= n; i++)
            System.out.print(r[i] + " ");
        System.out.println();
    }
    
    /**
      * 該方法計算最優解:
      * @param v 存儲每一個物品的價值
      * @param w 存儲每一個物品的重量
      * @param c 存儲揹包容量
      * @param n 物品數量
      * @param m 存儲構造的最優解
    */
    public static void knapsack(int[] v, int[] w, int c, int n, int[][] m)
    {
        //物品從第1件物品開始計算
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= c; j++)
            {
                if(j >= w[i])
                {
                    m[i][j] = max(m[i - 1][j], m[i - 1][j - w[i]] + v[i]);
                }
                else
                {
                    m[i][j] = m[i - 1][j];
                }
            }
        }
    }
    
    /**
      * 該方法構造最優解的生成過程:
      * @param m 存儲最優解的數組
      * @param w 存儲每一個物品的重量
      * @param c 存儲揹包容量
      * @param n 物品數量
      * @param x 存儲最優解生成過程的數組
    */
    public static void traceback(int[][] m, int[] w, int c, int n, int[] x)
    {
        for(int i = 1; i <= n; i++)
        {
            if(m[i][c] == m[i - 1][c]) //第i件物品爲未放入
            {
                x[i] = 0;
            }
            else //第i件放入
            {
                x[i] = 1;
                c -= w[i];
            }
        }
    }
    
    public static int max(int a, int b)
    {
        return a > b ? a : b;
    }
}

運行結果

結果示例

相關文章
相關標籤/搜索