01背包的动态规划解法(史无前例的详细)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32175379/article/details/73193725

写出 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,代表就用到它了
    }
}

猜你喜欢

转载自blog.csdn.net/qq_32175379/article/details/73193725