【彻底理解】【背包问题】0-1背包问题

有三种基本背包问题: 0/1背包问题、完全背包问题、多重背包问题
这里先来解决01背包问题

0-1背包问题描述

  • n个物品
  • 一个物品有两个属性(重量w和价值v)
  • 对于一个物品,我们有两个选择:0不拿、1拿
  • 载重限制C

要求:不超重情况下,拿到的价值最大

环境初始化

使用网上现成的:https://www.nowcoder.com/questionTerminal/708f0442863a46279cce582c4f508658
或者下面代码

package test;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 01 背包问题
 *
 * @author alan smith
 * @version 1.0
 * @date 2020/4/18 9:43
 */
public class Package01 {
    /**
     * 输入的数据
     * <p>
     * 第一行:载重C 商品个数n
     * 第二行:商品重量w1 商品价格v1
     * ~
     * 第n+1行:商品重量w(n+1) 商品价格v(n+1)
     */
    static String string = "1000 5\n" +
            "800 2 \n" +
            "400 5 \n" +
            "300 5 \n" +
            "400 3 \n" +
            "500 2 ";

    /**
     * 商品的封装
     */
    static class Good {
        public int weight;
        public int price;

        public Good(int weight, int price) {
            this.weight = weight;
            this.price = price;
        }

        @Override
        public String toString() {
            return "Good{" +
                    "weight=" + weight +
                    ", price=" + price +
                    '}';
        }
    }

    public static void main(String[] args) {
        // 默认值
        int MAX_GOOD_NUMBER = 60;// 最多多少个商品
        // 初始化
        Scanner in = new Scanner(string);
        // 载重
        int C = in.nextInt();
        // 有多少个物品
        int n = in.nextInt();
        // 解析出商品s
        Good[] goods = new Good[MAX_GOOD_NUMBER] ;
        for (int i = 0; i < n; i++) {
            int weight = in.nextInt();
            int price = in.nextInt();
            Good good = new Good(weight, price);
            goods[i] = good;
        }

        // 打印初始化环境
        System.out.println("载重C:"+C);
        System.out.println("商品个数n:"+n);
        System.out.println("全部商品:\n"+ Arrays.toString(goods));

        // 递归处理
        //int max = recursion(C, n, goods) ;
    }

}

递归

递推式(有时也称之为状态转移方程)

面对商品,我们有两个选择:买or不买

这样我们就可以开始套娃了

│
├─买商品1
│  ├─买商品2
│  │  ├─买商品3
│  │  │   ...
│  │  └─不买商品3
│  │      ...
│  └─不买商品2
│     ├─买商品3
│     │   ...
│     └─不买商品3
│         ...
└─不买商品1
   ├─买商品2
   │  ├─买商品3
   │  │   ...
   │  └─不买商品3
   │      ...
   └─不买商品2
      ├─买商品3
      │   ...
      └─不买商品3

设:

  • v i v_i vi 第i个商品价格
  • w i w_i wi 第i个商品重量
  • C C C 可用的容量
  • F ( i , C ) F(i,C) F(iC) 选择前i商品放入负重为C的包包,最大的总价格

那么就有递归式:
F ( i , C ) = m a x { F ( i − 1 , C ) , F ( i − 1 , C − w i ) + v i } F(i,C)=max\{ F(i-1,C), F(i-1, C-w_i)+v_i\} F(iC)=max{F(i1,C),F(i1,Cwi)+vi}

F(i,C)
│
├─买商品1 F(i-1, C-w_i)+v_i
│  ├─买商品2 
│  │  ├─...
│  │  └─...
│  └─不买商品2 
│     ├─...
│     └─...
└─不买商品1 F(i-1,C)
   ├─买商品2
   │  ├─...
   │  └─...
   └─不买商品2
      ├─...
      └─...

代码实现

package test;

import java.util.Arrays;
import java.util.Scanner;

/**
 * 01 背包问题
 *
 * @author alan smith
 * @version 1.0
 * @date 2020/4/18 9:43
 */
public class Package01 {
    /**
     * 输入的数据
     * <p>
     * 第一行:载重C 商品个数n
     * 第二行:商品重量w1 商品价格v1
     * ~
     * 第n+1行:商品重量w(n+1) 商品价格v(n+1)
     */
    static String string = "6 3\n" +
            "3 5\n" +
            "2 4\n" +
            "4 2";

    /**
     * 商品的封装
     */
    static class Good {
        public int weight;
        public int price;

        public Good(int weight, int price) {
            // 重量
            this.weight = weight;
            // 价值
            this.price = price;
        }

        @Override
        public String toString() {
            return "Good{" +
                    "weight=" + weight +
                    ", price=" + price +
                    '}';
        }
    }

    /**
     * 递归处理
     *
     * @param C     载重
     * @param n     商品数量
     * @param goods
     * @return 最大价值
     */
    private static int recursion(int C, int n, Good[] goods) {
        // 从0位上开始选商品
        return resursion(C, n, goods, 0);
    }

    /**
     * @param index 当前选择的商品
     */
    private static int resursion(int c, int n, Good[] goods, int index) {
        // 不符合条件,购买失败
        if (c <= 0 || n <= 0) {
            return 0;
        }

        // 不买
        // 选择下一个
        int noBuyPrice = resursion(c, n-1, goods, index + 1);

        // 买
        Good good = goods[index];
        int buyPrice = good.price;
        // 选择下一个
        buyPrice += resursion(c - good.weight, n - 1, goods, index + 1);

        // 判断返回
        int max = 0;
        if (c >= good.weight) {
            max = Math.max(buyPrice, noBuyPrice);
        } else {
            max = noBuyPrice;
        }
        return max;
    }


    public static void main(String[] args) {
        // 默认值
        int MAX_GOOD_NUMBER = 60;// 最多多少个商品
        // 初始化
        Scanner in = new Scanner(string);
        // 载重
        int C = in.nextInt();
        // 有多少个物品
        int n = in.nextInt();
        // 解析出商品s
        Good[] goods = new Good[MAX_GOOD_NUMBER];
        for (int i = 0; i < n; i++) {
            int weight = in.nextInt();
            int price = in.nextInt();
            Good good = new Good(weight, price);
            goods[i] = good;
        }

        // 打印初始化环境
        System.out.println("载重C:" + C);
        System.out.println("商品个数n:" + n);
        System.out.println("全部商品:\n" + Arrays.toString(goods));

        // 递归处理
        int max = recursion(C, n, goods);
        System.out.println(max);
    }
}

记忆搜索

todo

动态规划

todo

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骆言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值