java实现最通俗易懂的01背包问题

 

免费chatgpt使用网址 http://ffff.chat:2023  在设置中设置userID

 

 

这几天一直在想背包问题,昨天还有个学长专门讲了,但是还是不是很理解,今天我终于想通了背包问题,其实只要理解了这个思路,不管用什么语言,肯定是能编出来的。下面我就来介绍一下背包问题。

1.题目描述:

有如下5种物品,小明的书包最多只能装下8公斤的物品,小明特别贪心,思考怎么选择使自己书包能装下并且得到的价值最大。

物品1:6公斤     价值48元
物品2:1公斤     价值7元
物品3:5公斤     价值40元
物品4:2公斤     价值12元
物品5:1公斤     价值8元

2.解题思路:

其实我们正常思维,一般会想,我要尽量装满8公斤,把最大的价值求出来,可是这样的话,就需要用到递归,递归能解出来,只是算法难度高。但是什么是动态规划,动态规划就是逆着来,我要求装8公斤的物品怎么装使得价值最大。我可以先考虑装0公斤,最大价值,再考虑装1公斤最大价值,考虑装2公斤最大价值,装3公斤最大价值,把前面都记录下来。用另外一个temp[i][j]数组记录下来。i呢表示我现在出现的物品的数量,当i循环到最后一个数量的时候就结束了嘛。自己想象一下,我虽然有5件物品,先只给你一件,你判断能不能装下,能装下,那么你就看你装下这件物品,和不装下这件物品哪个价值高,那么记录下来即可。具体填下下面的表试下,真正会填表就差不多了

1
2
3
4
5
6
7
      0  1  2  3  4  5   6    7    8
      0  0  0  0  0  0   0    0    0
6 48  0  0  0  0  0  0   48  48   48
1 7   0  7  7  7  7  7   48  55   55
5 40  0  7  7  7  7  40  48  55   55
2 12  0  7  12 19 19 40  48  55   60
1 8   0  8  15 20 27 40  48  56   63

 

这个表是怎么来的呢?,举个例子,当我横着一排一排填,因为最开始只掉一件物品,开始掉重量是6的物品,到6的时候就能装下了,所以temp[1][6]=48,另外7,8也只有这一件物品填。所以还是一样的。

接下来掉第二个物品,掉下1这个物品了,1的价值是7,也就是temp[2][1] = 7。后面一直到temp[2][5]都是等于7。 重点重点来了,到了temp[2][6]的时候怎么办呢?我们的当然一看就是,我要选第一件物品,它的价值是48,可是选了第一件物品,背包就满了,就不能装第二件重量为1的物品了,所以temp[2][6] = 48。

我们人可以这样思考,关键就来了,关键就是怎么让计算机也可以这样思考呢,我们就需要用代码。其实仔细想想,我掉第二件物品了,判断如果不能装下,那么temp[2][j] = temp[2][j-1] //记住j表示的是我背包现在最大只能装j这么多,那既然这个物品装不下,那么当然不能装了。如果我当前物品重量小于j,那么我就可以选择是装还是不装呢?只要比较装还是不装哪个价值大就行了。如果不装的话价值这个时候的最大价值是不会变的,因为都不装嘛,也就是,temp[2][j] = temp[2-1][j] 。如果我装的话,关键是这个,还是到刚才的到第二件物品的价值为6的时候考虑,如果我装下重量1这个物品,temp[2][6] = temp[2-1][6 - 这个物品的重量] + 物品的价值  //

其实我   temp[2-1][6-这个物品重量]表示我还没装这个物品之前的价值腾出装这个物品的空间,然后加上这个物品的价值进行比较。关键是之前的每一个状态都用数组给记录下来了。关键代码先看一下,结合代码再理解

1
2
3
4
5
6
7
8
9
for(int i=1;i<6;i++) {
    for(int j=1;j<9;j++) {
        if(w[i]<=j) {
            temp[i][j] = Math.max(temp[i-1][j], temp[i-1][j-w[i]]+v[i]); //其实就是比较物品选还是不选哪种价值大。
        }else {
            temp[i][j] = temp[i-1][j];//第i件物品不能放
        }
    }
}

 这个理解了,相信你自己也能编出这段代码来了。

3.代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package 背包问题;
 
import java.util.Scanner;
 
/*
 *
最多可以放8公斤的物品
物品1:6公斤   价值48元
物品2:1公斤   价值7元
物品3:5公斤   价值40元
物品4:2公斤   价值12元
物品5:1公斤   价值8元
 
      0  1  2  3  4  5   6    7    8
      0  0  0  0  0  0   0    0    0
6 48  0  0  0  0  0  0   48  48   48
1 7   0  7  7  7  7  7   48  55   55
5 40  0  7  7  7  7  40  48  55   55
2 12  0  7  12 19 19 40  48  55   60
1 8   0  8  15 20 27 40  48  56   63
        
 */
public class Test01 {
    public static void main(String[] args) {
        //定义一个数组a[i][j] = a[i]                 i表示当前物品的序号选上,j表示这个位置能得到的最大值
        //选或者不选动态规划
        Scanner scn = new Scanner(System.in);
        int [] w = new int[6];//表示每件物品的重量
        int [] v = new int[6];//表示每件物品的价值
        for(int i=1;i<6;i++) {
            w[i] = scn.nextInt();//输入重量
            v[i] = scn.nextInt();//输入价值
        }
         
        int [][] temp = new int[6][9];   //8表示背包最多能放8公斤的重量
        for(int j=0;j<9;j++) {  //初始化每一行
            temp[0][j] = 0;
        }
        for(int i=1;i<6;i++) {  //背包的重量为0的时候,最大价值肯定是0
            temp[i][0] = 0;
        }
         
        for(int i=1;i<6;i++) {  //从第一个物品开始选,记录我选了前面出现的物品,背包重量从1-8的能选上的最大的值
            for(int j=1;j<9;j++) { //当i循环到最后一层5的时候,也就是得到了,我5件物品都选上的时候的最大的值
                if(w[i]<=j) { //重量比这个状态小,那么就能放。 那么就只是放与不放,看是放重量大,还是不放重量大
                    temp[i][j] = Math.max(temp[i-1][j], temp[i-1][j-w[i]]+v[i]);
                }else {
                    temp[i][j] = temp[i-1][j];//第i件物品不能放
                }
            }
        }
        for(int i=0;i<6;i++) {
            for(int j=0;j<9;j++) {
                System.out.printf("%-5d",temp[i][j]);
            }
            System.out.println();
        }
    }
}

 

posted @   my日常work  阅读(12177)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示