01揹包的動態規劃解法(史無前例的詳細)

寫出 0-1 揹包問題的自底向上非遞歸的動態規劃算法。
輸入: 首先輸入 物品的 個數 n , 然後輸入 揹包的 容量 c , 再依次輸入每個 物品的
重量 wi , 最後依次輸入每個 物品的 價值 vi 。 注意: 所有值都不能隨機生成 ! ! !
輸出:物品的選擇向量。如:(1,0,0,1,1) 等。
示例:輸入:4 5 2 1 3 2 12 10 20 15 輸出:1 1 0 1 或(1,1,0,1 )
這裏寫圖片描述

這裏寫圖片描述
詳細解法:

package com.ccc;

import java.util.Scanner;

public class aaaaa {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Scanner  sc=new Scanner(System.in);
         int n=sc.nextInt(); //物品個數
         int c=sc.nextInt();//揹包容量
         int m[][]=new int[n+1][c+1];//最大價值
         int v[]=new int[n+1];//記錄每個物品的價值
         int w[]=new int[n+1];//記錄每個物品的重量
         int x[]=new int[n+1];//記錄物品是否被放入揹包
         for (int i = 1; i <=n; i++)//存入每個物品的重量
         {
            w[i]=sc.nextInt();
         }
         for (int i = 1; i <=n; i++)//存入每個物品的價值
         {
            v[i]=sc.nextInt();
         }
         pa(c, n, v, w, m);
         out(n, c, x, w, m);
         for (int i = 1; i <= n; i++)
         {
            System.out.print(x[i]+" ");
         }
    }
  // 揹包問題的自底向上的算法
    public  static  void pa(int c,int n,int v[],int w[],int m[][])
    {
        //---------------------------處理最後一行-----------------------------------
          int jMax=Math.min(w[n]-1, c);//  這個用來避免一個物品的重量超大,導致揹包裝不下,例如第四個物品重量爲6,而揹包容量爲3,
          //所以表圖中的最後一行應該全部爲0,這時jMax爲c,如果沒這個那麼用w[n]-1的話,那麼m可能越界了
          for (int j = 0; j <=jMax; j++)
          {
              m[n][j]=0;//給最後一行的列數(即揹包容量)不到w[n]的賦值爲0,(價值爲0)
          }
          for (int j =w[n]; j <= c; j++)
          {
              m[n][j]=v[n];//當揹包的容量足夠容納w[n]時,將其價值賦值給他們
          }
          //-------------------------處理最後一行以上的-----------------------
          for (int i = n-1; i>=1; i--)
          {
              jMax=Math.min(w[i]-1, c);
              for (int j = 0; j <=jMax; j++)
              {
                  m[i][j]=m[i+1][j];//當列數(即揹包容量)不到w[i]時,那麼將其下面那一行並且同列的這個值賦值給他,這個值可能爲0,可能已經有值
              }
              for (int j =w[i]; j <= c;j++)
              {
                  m[i][j]=Math.max(m[i+1][j],m[i+1][j-w[i]]+v[i]);//如果當前的列數(即揹包容量)可以容納當前物品時,
                  //那麼看放入這個物品產生的最大價值大還是不放大,不放的話,那麼他的價值就是下行同列的價值,放入的話,即當前揹包容量減去當前這個物品所佔的揹包容量
                  //加上該物品的價值,看誰大,哪個價值大就選哪個,至於爲什麼是第i+1行,因爲你是放入物體B,看放入B後的剩餘的容量夠不夠放下物品A,A在i+1行
              }
         }
    }
    //算法的最優解
    public static void out(int n,int c,int x[],int w[],int m[][])
    {
        for (int i = 1; i < n; i++)//<n是因爲下面是i和i+1比較
        {
            if(m[i][c]==m[i+1][c])//相等的話說明這個物品沒什麼用,沒用到
            {
                x[i]=0;
            }
            else //不相等的話說明這個物品用到了,即放到揹包裏了
            {
              x[i]=1;
              c=c-w[i];//用到這個物品了,那麼減去這個物品代表的重量,看剩下的都是用到了誰(然後就是循環看)
            }
         }
         x[n]=(m[n][c]==0?0:1);//因爲是最後一行,所以如果他不是0,代表就用到它了
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章