首页 > 其他分享 >什么是背包问题?

什么是背包问题?

时间:2023-01-30 10:31:55浏览次数:33  
标签:背包 weight 什么 问题 Item 物品 贪心

本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注!

作者| 慕课网精英讲师 JdreamZhang

假设我们一共有 n 种物品,每种物品 i 的价值为 vi,重量为 wi,我们有一个背包,背包的容量为 c(最多可以放的物品重量不能超过 c),我们需要选择物品放入背包中,使得背包中选择的物品中总价值最大,在这里每个物品可以只选择部分。这便是我们常说的背包问题

背包问题是一种常见的可以用贪心算法进行求解的问题,接下来,就让我们看看如何利用贪心算法解决背包问题。

1. 贪心算法求解背包问题

首先,这里我们考虑背包的容量为 30,并给出这个问题中我们考虑到的各类物品及对应的重量和价值,如下:

物品 n (i)

1

2

3

4

5

重量 w (i)

10

5

15

10

20

价值 v (i)

20

30

15

25

10

回顾一下我们在贪心算法介绍中提到的,能够应用贪心算法求解的问题需要满足两个条件:最优子结构贪心选择,接下来,我们就具体来看看在背包问题中的最优子结构和贪心选择分别是什么。

首先,如果一个问题的最优解包含其子问题的最优解,则此问题具备最优子结构的性质。问题的最优子结构性质是该问题是否可以用贪心算法求解的关键所在。对于背包问题,很显然它是满足最优子结构性质的,因为一个容量为 c 的背包问题必然包含容量小于 c 的背包问题的最优解的。

其次,我们需要考虑在背包问题中,我们应该按照什么样的贪心选择进行选取。很显然,如果要使得最终的价值最大,那么必定需要使得选择的单位重量的物品的价值最大。所以背包问题的贪心选择策略是:优先选择单位重量价值最大的物品,当这个物品选择完之后,继续选择其他价值最大的物品。

这里的背包问题可以用贪心算法实现,是因为背包选择放入的物品可以进行拆分,即并不需要放入整个物品,可以选择放入部分物品,我们这样的背包选择问题为部分背包问题(可以只选择物品的部分),与之对应的另一种背包问题为 0-1 背包问题,这个时候整个物品不可以拆分,只可以选择放入或者不放入,0-1 背包问题用贪心算法并不能求得准确的解,需要用动态规划算法求解。

背包问题求解详解:

在这里,我们按照优先选择单位重量价值最大的物品,所以第一步需要计算单位每个物品的单位价值,如下:

unitValue(1) = 20/10 = 2
unitValue(2) = 30/5 = 6
unitValue(3) = 15/15 = 1
unitValue(4) = 25/10 = 2.5
unitValue(5) = 10/20 = 0.5
代码块12345

所以我们有:

unitValue(2) > unitValue(4) > unitValue(1) > unitValue(3) > unitValue(5)
代码块1

当考虑背包的容量为 30 时, 我们发现可以按照物品的单位价值进行依次放入,直至背包容量放满或者物品放完为止,放入的过程如下:

物品类型

放入重量

背包使用容量

背包剩余容量

2

5

5

25

4

10

15

15

1

10

25

5

3

5

30

0

按照如上步骤我们简单分析了一下背包问题的求解过程,接下来,我们看一下如何用代码实现背包问题。

2.JAVA 代码实现

在说明求解背包问题的整个过程之后,接下来,我们看看如何用 java 代码实现背包问题的求解。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Knapsack {

/**
* 物品内部类
*/
private static class Item implements Comparable<Item>{
int type;
double weight;
double value;
double unitValue;

public Item(int type, double weight){
this.type = type;
this.weight = weight;
}

public Item(int type, double weight,double value){
this.type = type;
this.weight = weight;
this.value = value;
this.unitValue = value/weight;
}

@Override
public int compareTo(Item o) {
return Double.valueOf(o.unitValue).compareTo(this.unitValue);
}
}

public static void main(String[] args){
//背包容量
double capacity = 30;
//物品类型初始化数组
int[] itemType = {1,2,3,4,5};
//物品重量初始化数组
double[] itemWeight = {10,5,15,10,30};
//物品价值初始化数组
double[] itemValue = {20,30,15,25,10};

//初始化物品
List<Item> itemList = new ArrayList<>();
for(int i=0;i<itemType.length;i++){
Item item = new Item(itemType[i],itemWeight[i],itemValue[i]);
itemList.add(item);
}
//物品按照单价降序排序
Collections.sort(itemList);

//背包选择
List<Item> selectItemList = new ArrayList<>();
double selectCapacity = 0;
for(Item item : itemList){
if( (selectCapacity + item.weight) <= capacity){
selectCapacity = selectCapacity + item.weight;
Item selectItem = new Item(item.type,item.weight);
selectItemList.add(selectItem);
}else {
Item selectItem = new Item(item.type, capacity-selectCapacity);
selectItemList.add(selectItem);
break;
}
}

//选择结果输出
for (Item item : selectItemList){
System.out.println("选择了类型:"+ item.type+" 的物品,重量为:"+item.weight);
}

}
}
代码块1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374

运行结果如下:

选择了类型:2 的物品,重量为:5.0
选择了类型:4 的物品,重量为:10.0
选择了类型:1 的物品,重量为:10.0
选择了类型:3 的物品,重量为:5.0
代码块1234

代码中第 10 行至第 31 行定义了物品的一个内部类,用来存储一个物品的类型、重量、价值、单位重量的价值,并且实现在其中实现了一个对比函数。代码的第 35 至 42 行对应着开始的背包问题的初始化工作,分别初始化了背包容量、物品类型、物品重量、物品价值。代码的第 44 行至 51 行将所有物品按照物品内部类的格式加入数组,并且按照物品单位重量的价值进行降序排序。代码的第 53 行至第 66 行,按照背包问题的贪心选择方法选择对应的物品,并记录选择的物品类型及重量,放入到选择的物品列表中 ,代码的 69 行 71 行输出相关的物品选择结果。

3 小结

本篇文章主要利用了贪心算法处理背包问题,需要大家掌握贪心算法解决背包问题的流程,并且可以自己用代码实现背包问题的求解。在学习完这篇文章后,我们通过背包问题这一实例介绍了贪心算法的实际应用,相信一定可以帮助大家更好的理解贪心算法。

欢迎关注「慕课网」,发现更多IT圈优质内容,分享干货知识,帮助你成为更好的程序员!


标签:背包,weight,什么,问题,Item,物品,贪心
From: https://blog.51cto.com/u_15771948/6026099

相关文章

  • 关于spring给类类型赋值的问题
    提问: 有无好兄弟能解释一下这啥情况,我调用第一个bean,第一个bean调用外部bean也就是第二个bean,但是第二个bean的值是第三个bean里的级联值?    解答: 创建最下......
  • 春哥博客 - 解决某些应用程序阻止了IDM集成到浏览器中的问题
       每次打开IDM都会弹出:某些应用程序阻止了IDM集成到浏览器中的提示,尝试了腾讯管家的截图弹窗拦截,也没奏效 后来卸载重装idm,安装时使用管理员权限来安装,后来重启......
  • 第一次内存不兼容问题
    厂商:宏基类型:笔记本型号:记不清太乱cpu:amdr5pro4650u问题:内存不同厂商不同颗粒数,更换一致后解决。大概情况:两根16g内存都是寨条,前后购买用在也是宏基的本子,cpu是i5......
  • 人工智能要解决的问题
    人工智能要解决的问题包括哪些呢?数据分类文本识别语音识别生物识别图片分析视频分析创造文本创造图片创造视频创造物品? 有些已实现;有些已成熟;有些未......
  • 2023 年该学点什么技术?「GitHub 热点速览 v.23.03」
    春节期间,小鱼干读了一篇万字回顾数据库行业的文章,在文字缝隙里我看见了两个词:AI+和数据两个词(当然数据是废话,毕竟是一个数据库的回顾文)。在GitHub上热点趋势上,可见到A......
  • 3e棕垫什么意思
    3e椰棕床垫是指节能环保的床垫。3e椰棕床垫中的3e,是“Energy”、“Efficiency”、“Engine”三个英文的缩写,代表的意思分别是节能、高效、低功耗,也就是说,3e是一个环保认证......
  • 记一次系统迁移遇到的中文字符串排序问题
    背景不久前,迁移了一个framework项目到.netcore上面,部署也从Windows的IIS到linux的容器化。期间遇到了一个关于中文字符串排序的问题,在这里记录一下。复现与......
  • 为什么wait()需要在同步代码块内使用
    我们还是通过源代码和代码注释来学习这个问题我们先来看看wait方法的注释,这里截取最根源的native方法给的注释Causesthecurrentthreadtowaituntileitheranother......
  • 总是想要写点什么
    总是想要写点什么,但下笔却不知该说些啥;总是想要说点什么,但一切准备就绪才发现无人无处诉说;总是想要一鸣惊人,却发现自己并未不同于芸芸众生;总是想要创造不凡,却发现自己只......
  • 记录项目报错问题——mybatisPlus主键重复报错
    mybatisPlus主键重复报错问题错误信息:org.springframework.dao.DuplicateKeyException:###Errorupdatingdatabase.Cause:java.sql.SQLIntegrityConstraintViola......