解决背包问题:组合优化的应用与建模方法

news2024/11/17 21:27:57

前言

在之前发布的智能解决装箱问题:使用优化算法实现高效包装一文中,我们已经介绍了什么是组合优化问题。这里仅简述:
组合优化是数学优化的一支,专注于从有限集合中选取元素的最优化问题。它涉及将一组对象组合在一起,以满足特定条件并优化某个目标函数,即在所有可能的组合中找到最有利的一个。

本文将以一个简化的背包问题为例,来讲解采用数学规划的方法来解决背包这个组合优化问题。

背包问题

背包问题(Knapsack Problem)和装箱问题(Packing Problem)是两类经典的组合优化问题。虽然在概念上有所相似,都涉及物品的选择和分配,它们的优化目标和具体应用场景却有所不同。

背包问题
目标是在不超过背包容量限制的条件下,选取总价值最大化的物品组合。应用场景广泛,如行李打包、物流、购物选择、广告投放、投资组合、资源分配。

装箱问题
目标是在尽量减少容器数量或最小化容器空余容量的前提下将物品装入箱子。常见的应用场景包括集装箱装载、仓库货物分配、内存分配等。

最明显的区别,是优化目标:

  • 背包问题:最大化所装物品的价值
  • 装箱问题:最小化容器数量

问题描述以及数学规划建模

image.png
假设小美要出远门长住几个月,她带了4个包,需要带更有价值的物品。有一堆物品可以带,如果忽略物品刚性形状,我们假设所有物品都可以变形,评估物品体积、重量和有用价值如表格 data/items-1.csv,部分内容如下:


物品ID物品重量(g)物品体积(cm^3)价值因子
1161180714
2794410955
32554952-4
4841577388
100753123149

物品和背包属性如下:

  • 物品集合 I I I
    • 它的描述信息参数是 重量 w i w_{i} wi、尺寸 s i s_{i} si 和 价值 v i v_{i} vi
  • 假设有背包集合 B B B
    • 它的描述信息参数是 承重上限 w b , m a x w_{b,max} wb,max 、 尺寸上限 s b , m a x s_{b,max} sb,max

变量:

  • 货物如何摆放,设置 0-1 变量 x i , b x_{i,b} xi,b,其中 i ∈ I i \in I iI, b ∈ B b \in B bB。 当变量取值为1的时候,则代表物品装进该背包,为0的时候则不放置。

建模目标和约束条件:

目标函数: max ⁡ ∑ i ∈ I , b ∈ B x i , b ⋅ v i \max \sum_{i \in I, b \in B} x_{i,b} \cdot v_{i} maxiI,bBxi,bvi

约束条件:

  • 每个货物最多只能放一个位置: ∑ b ∈ B x i , b ≤ 1 , ∀ i ∈ I \sum_{b \in B} x_{i,b} \leq 1, \forall i \in I bBxi,b1,iI
  • 每个货车上,装载的货物重量和体积限制:
    • ∑ i ∈ I x i , b ⋅ w i ≤ w b , m a x , ∀ b ∈ B \sum_{i \in I} x_{i,b} \cdot w_{i} \leq w_{b,max}, \forall {b \in B} iIxi,bwiwb,max,bB
    • ∑ i ∈ I x i , b ⋅ s i ≤ s b , m a x , ∀ b ∈ B \sum_{i \in I} x_{i,b} \cdot s_{i} \leq s_{b,max}, \forall {b \in B} iIxi,bsisb,max,bB

MindOpt APL 编程和求解

MindOpt APL是达摩院研发的代数建模语言,国内首款!语法简单!点击了解>>

使用MindOpt APL进行建模和求解。导入背包和物品的数据,定义变量、目标函数和约束,调用求解器获取最优解。

clear model;
option modelname knapsackproblem_01; #定义存储文件名

# ----------建模--------Start----
# knapsackproblem_01.mapl

## 导入数据-------
print "导入数据-------";

param fileDir = "data/";

# 物品数据
param ItemsFilename = "items-1.csv"; # 有10份数据,名字分别是 items-1.csv,items-2.csv……
set Items = {read fileDir+ItemsFilename as "<1n>" skip 1}; #读取货物序号
param ItemWeight[Items] = read fileDir+ItemsFilename as "<1n> 2n" skip 1; #读取物品的重量,单位克g
param ItemSize[Items] = read fileDir+ItemsFilename as "<1n> 3n" skip 1; #读取物品的尺寸,单位立方厘米cm^3
param ItemValue[Items] = read fileDir+ItemsFilename as "<1n> 4n" skip 1; #读取物品的价值,有正有负

print "数据:{}"%ItemsFilename;
print "- 总共有{}个可选择物品,总重量{}g,总体积{}cm^3,总价值{},其中正价值总和{},负价值总和{}"
    % card(Items),
    sum{i in Items}ItemWeight[i],
    sum{i in Items}ItemSize[i],
    sum{i in Items}ItemValue[i],
    sum{i in Items with ItemValue[i] >0 } ItemValue[i],
    sum{i in Items with ItemValue[i] <=0 } ItemValue[i];


# 背包数据
param BagsFilename = "bags.csv";
set Bags = {read fileDir+BagsFilename as "<1n>" skip 1}; #读取货物序号
param BagWeightCapacity[Bags] = read fileDir+BagsFilename as "<1n> 2n" skip 1; #读取包的重量承重,单位克g
param BagSizeCapacity[Bags] = read fileDir+BagsFilename as "<1n> 3n" skip 1; #读取包的体积容量,单位立方厘米cm^3

print "- 总共有{}个可选择物品,承重上限{}g,容积上限{}cm^3"
    % card(Bags),
    sum{b in Bags} BagWeightCapacity[b],
    sum{b in Bags} BagSizeCapacity[b];

## 数学建模-------
print  "数学建模--------------";


# 变量----
var x_Item2Bag[Items*Bags]  >= 0 binary; #物品放哪个包

# 目标----
# 目标函数:最大化所带物品的价值
maximize TotalValue: sum { <i,b> in Items*Bags } x_Item2Bag[i,b] * ItemValue[i];



# 每个物品最多只能放一个位置,且至少是一个位置
subto constraint_0:
    forall {i in Items}
         sum {b in Bags} x_Item2Bag[i,b] <= 1;

# 每个包的容量限制
# 重量
subto constraint_1:
    forall {b in Bags}
            sum { i in Items} x_Item2Bag[i,b] * ItemWeight[i] <= BagWeightCapacity[b];

# 体积
subto constraint_2:
    forall {b in Bags}
            sum { i in Items} x_Item2Bag[i,b] * ItemSize[i] <= BagSizeCapacity[b];

#求解
print  "调用求解器求解--------------";
option solver mindopt;     # (可选)指定求解用的求解器,默认是MindOpt
#option mindopt_options 'max_time=600'; #设置求解器参数
#option mindopt_options 'print=0'; #设置求解器输出级别,减少过程打印
solve;         # 求解

# 结果打印和检查结果
print "结果打印和存文件--------------";
#display; 

print "- 带的物品数 = ",sum { <i,b> in Items*Bags } x_Item2Bag[i,b];
print "- 总价值是 = ",sum { <i,b> in Items*Bags } x_Item2Bag[i,b] * ItemValue[i];



print "- 包里面摆放物品清单:";
print "|背包ID|物品ID|体积|重量|价值|";
print "|--|--|--|--|--|";
# 由于打印太多,只打印小报包的,如需打印全部,可以删除`with b>2 `
forall { b in Bags with b>2 }
    forall { i in Items with  x_Item2Bag[i,b]>= 0.5}
        print "|{}|{}|{}|{}|{}|"%b,i,ItemWeight[i],ItemSize[i],ItemValue[i];
print "|……|……|……|……|……|";

# 存文件
print "背包ID,物品ID,体积,重量,价值": "每个背包的物品清单.csv";
close "每个背包的物品清单.csv";
forall { b in Bags }
    forall { i in Items with  x_Item2Bag[i,b] >= 0.5}
        print "{},{},{},{},{}"%b,i,ItemWeight[i],ItemSize[i],ItemValue[i] >> "每个背包的物品清单.csv";
close "每个背包的物品清单.csv";

print "- 结果文件存储在: [每个背包的物品清单.csv](每个背包的物品清单.csv)";

运行上述代码结果如下:

导入数据-------
数据:items-1.csv
- 总共有100个可选择物品,总重量44795g,总体积326428cm^3,总价值4342,其中正价值总和4411,负价值总和-69
- 总共有4个可选择物品,承重上限34000g,容积上限237000cm^3
数学建模--------------
调用求解器求解--------------
Running mindoptampl
wantsol=1
MindOpt Version 1.1.1 (Build date: 20240306)
Copyright (c) 2020-2024 Alibaba Cloud.

Start license validation (current time : 27-MAR-2024 16:13:18).
License validation terminated. Time : 0.008s

Model summary.
 - Num. variables     : 400
 - Num. constraints   : 108
 - Num. nonzeros      : 1200
 - Num. integer vars. : 400
 - Bound range        : [1.0e+00,1.2e+05]
 - Objective range    : [1.0e+00,9.9e+01]

Branch-and-cut method started.
Original model: nrow = 108 ncol = 400 nnz = 1200
Tolerance: primal = 1e-06 int = 1e-06 mipgap = 0.0001 mipgapAbs = 1e-06
Limit: time = 1.79769313486232e+308 node = -1 stalling = -1 solution = -1
presolver terminated; took 0 ms
presolver terminated; took 9 ms
Parallelism: root=2, tree=2
      accept new sol: obj 0 bnd vio 0 int vio 0 mipgap inf time 0
      accept new sol: obj -4201 bnd vio 0 int vio 0 mipgap 2.57295881932873 time 0
Model summary.
 - Num. variables     : 294
 - Num. constraints   : 94
 - Num. nonzeros      : 882
 - Bound range        : [1.0e+00,1.2e+05]
 - Objective range    : [1.0e+00,9.9e+01]
 - Matrix range       : [1.0e+00,6.0e+03]

Presolver started.
Presolver terminated. Time : 0.000s

Simplex method started.
Model fingerprint: mdXZv92dj5WZ3Nmb

    Iteration       Objective       Dual Inf.     Primal Inf.     Time
            0    -1.50100e+04      0.0000e+00      3.9240e+02     0.00s  
          137    -4.30372e+03      0.0000e+00      0.0000e+00     0.00s  
Postsolver started.
Simplex method terminated. Time : 0.001s

      accept new sol: obj -4211 bnd vio 0 int vio 0 mipgap 0.0220180858248353 time 0
      accept new sol: obj -4290 bnd vio 0 int vio 0 mipgap 0.00319770615579984 time 0
Root relaxation: -4303.71815940838 iteration = 137 time = 0.002
 #node(P:0 Q:0) #(dual:-4303.72 best:-4290 gap:0.32%) #time = 0
      accept new sol: obj -4299 bnd vio 0 int vio 2.81374923361e-15 mipgap 0.00109750160697402 time 0
      accept new sol: obj -4303 bnd vio 6.66133814775094e-16 int vio 0 mipgap 0.000166897375872955 time 1
- Solution pool    : 5
Branch-and-cut method terminated. Time : 1.913s


OPTIMAL; objective 4303.00

Completed.
结果打印和存文件--------------
- 带的物品数 = 75
- 总价值是 = 4303
- 包里面摆放物品清单:
|背包ID|物品ID|体积|重量|价值|
|--|--|--|--|--|
|3|13|650|4889|67|
|3|28|684|5395|36|
|3|38|236|1966|62|
|3|47|379|3467|24|
|3|48|317|3168|94|
|3|74|402|5083|58|
|4|73|250|35|54|
|4|86|50|2411|67|
|4|95|536|510|13|
|……|……|……|……|……|
- 结果文件存储在: [每个背包的物品清单.csv](每个背包的物品清单.csv)

高阶方案尝试

此案例发布在云上建模平台中读者可尝试复制本项目,增加难度进行调试。比如:

  1. 在平台中的data文件夹中,我们提供了不同的item.csv数据,如 data/items-2.csv,观察不同数据的结果区别。
  2. 增加物品的其他信息,如类别,标记每个类别里面至少带的数量。
  3. 将此模型推广到其他场景,比如:
    • 在线广告:选择最优化的广告投放组合,以最大化点击率或转化率。
    • 股票投资:如何在有限的资金下,挑选出能带来最大收益的股票组合。
    • 资源分配:如何在有限的资源下,最大化利益。
    • 云计算:在有限的资源下,为各个任务分配最优的资源组合。
    • 学术研究:在有限的资源和时间下,选择最有价值的研究课题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1665121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansible之Playbook的Template模板和tags标签

文章目录 一、Template模块1、准备template模板文件2、修改主机清单文件3、编写playbook4、执行playbook5、准备测试网页6、访问测试 二、tags模块1、编写脚本2、执行tags"xx01"3、执行tags"xx02" 一、Template模块 Jinja是基于Python的模块引擎。Templat…

黑马程序员HarmonyOS4+NEXT星河版入门到企业级实战教程【18~23】

视频0~17的笔记 页面路由 实现不同页面之间的跳转和数据传递。 页面栈。上限是32个页面&#xff0c;使用router.clear()可以清空页面栈释放内存。 两种跳转模式&#xff1a; 参数一致&#xff0c;都是三个参数 router.pushUrl()&#xff0c;新页面压入页面栈&#xff0c;可以…

GPT-SoVits:语音克隆,语音融合

首发网站 https://tianfeng.space 前言 零样本文本到语音&#xff08;TTS&#xff09;&#xff1a; 输入 5 秒的声音样本&#xff0c;即刻体验文本到语音转换。少样本 TTS&#xff1a; 仅需 1 分钟的训练数据即可微调模型&#xff0c;提升声音相似度和真实感。跨语言支持&…

网易Airtest集群方案大揭秘:小型便携式集群方案来啦

一、前言 中小型企业/工作室搭建便携设备集群的制胜法宝是什么&#xff1f;当然非网易Airtest便携式机柜莫属啦。得益于广大企业客户对我们便携式集群的支持&#xff0c;我们团队也一直在坚持优化小型的便携式集群方案&#xff0c;短短2年时间&#xff0c;我们的便携式机柜已经…

oracle 新_多种块大小的支持9i

oracle 新_多种块大小的支持 conn sys/sys as sysdba SHOW PARAMETER CACHE ALTER SYSTEM SET DB_CACHE_SIZE16M; ALTER SYSTEM SET DB_4K_CACHE_SIZE8M; CREATE TABLESPACE K4 DATAFILE F:\ORACLE\ORADATA\ZL9\K4.DBF SIZE 2M BLOCKSIZE 4K; CREATE TABLE SCOTT.A1 TABLESP…

【csdn】数据工程实践:从网络抓取到API调用,解析共享单车精准投放所需要的数据

共享单车作为一种便捷的出行方式&#xff0c;有效缓解了“最后一公里”难题&#xff0c;同时促进了绿色出行。然而&#xff0c;在高峰时段&#xff0c;供需不均和停车难成为普遍挑战&#xff0c;尤其是在通勤时间&#xff0c;热门地点如地铁站附近和办公区常常面临车辆短缺或停…

【C语言】/*操作符(上)*/

目录 一、算数操作符&#xff1a;、-、*、/、% 1.1 和 - 1.2 * 1.3 / 1.4 % 二、赋值操作符&#xff1a; 和符合赋值 2.1 连续赋值 2.2 复合赋值(自操作) 三、单目操作符&#xff1a;、--、(正号)、-(负号) 3.1 和 -- 3.1.1 前置 3.1.2 后置 3.1.3 前置-- …

汽车EDI:安通林Antolin EDI 项目案例

安通林&#xff08;Antolin&#xff09;是一家全球性的汽车零部件制造商&#xff0c;专注于汽车内饰系统和零部件的生产&#xff0c;致力于创新和采用先进的技术。近年来 安通林Antolin 推动其供应商部署EDI系统&#xff0c;使得双方能够通过EDI传输业务单据&#xff0c;极大提…

IDEA使用技巧2—发布web项目

作者&#xff1a;私语茶馆 1.War包类型 发布Web项目有两种模式&#xff1a;war和war exploded&#xff0c; war模式&#xff1a;将WEB工程以包的形式上传到服务器 &#xff1b;war exploded模式&#xff1a;将WEB工程以当前文件夹的位置关系上传到服务器&#xff1b; war ex…

java日历类概述

Java中的Calendar类位于java.util包下&#xff0c;它是一个抽象类&#xff0c;用于表示和管理日期及时间。Calendar类并不是直接实例化的&#xff0c;而是通过其提供的静态方法来获取实例。通常情况下&#xff0c;当你尝试创建一个Calendar实例时&#xff0c;实际上你得到的是G…

在 Navicat 17 中探索表配置文件

距离 Navicat 17&#xff08;英文版&#xff09;的发布还有不到一周的时间&#xff0c;现在是深入研究新的表配置文件功能的最佳时机。它允许我们保存经常用于表的筛选、排序和列显示的不同组合。所以&#xff0c;事不宜迟&#xff0c;让我们开始吧&#xff01; 创建表配置文件…

LeetCode 106.从中序与后序遍历序列构造二叉树

LeetCode 106.从中序与后序遍历序列构造二叉树 1、题目 题目链接&#xff1a;106. 从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并…

思维导图在线怎么制作?推荐这些工具

思维导图在线怎么制作&#xff1f;在如今的快节奏时代中&#xff0c;思维导图作为一种高效的信息组织与思考工具&#xff0c;受到了广泛的应用。在线制作思维导图成打破了时间和空间的限制&#xff0c;使得团队协作变得更加便捷&#xff0c;个人创作也更为灵活。以下是四款备受…

2024年生物医学、医学图像与信号处理国际会议(ICBMISP2024)

2024年生物医学、医学图像与信号处理国际会议(ICBMISP2024) 会议简介 2024年国际生物医学、医学成像和信号处理会议&#xff08;ICBMISP2024&#xff09;很高兴邀请您提交主题为“生物医学、医学图像和信号处理的当前挑战和未来前景”的原稿。通过ICBMISP2024&#xff0c;生物…

鸿蒙开发接口Ability框架:【DataAbilityHelper模块(JS端SDK接口)】

DataAbilityHelper模块(JS端SDK接口) 说明&#xff1a; 本模块首批接口从API version 7开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 本模块接口仅可在FA模型下使用。 使用说明 使用前根据具体情况引入如下模块 import featureAbility from …

i春秋-Backdoor

题目 考点 git源码泄露 Linux文件恢复 代码审计 http 解题 参考wp https://blog.csdn.net/cbhjerry/article/details/105791056https://www.pianshen.com/article/19461342501/扫描 题目给出提示&#xff1a;敏感文件泄漏 于是使用dirsearch扫一下 python dirsearch.py -…

ASP.NET一个简单的媒体播放器的设计与实现

摘 要 本论文所描述的播放器是在Microsoft Visual Studio .NET 2003平台下利用Visual Basic.NET语言完成的。使用Visual Basic.NET提供的Windows Media Player控件以及文件处理&#xff0c;最终实现一款别致的&#xff0c;贴近用户操作习惯的媒体播放器。 该播放器实现了对WAV…

原子学习笔记4——GPIO 应用编程

一、应用层如何操控 GPIO 与 LED 设备一样&#xff0c;GPIO 同样也是通过 sysfs 方式进行操控&#xff0c;进入到/sys/class/gpio 目录下&#xff0c;如下所示&#xff1a; gpiochipX&#xff1a;当前 SoC 所包含的 GPIO 控制器&#xff0c;我们知道 I.MX6UL/I.MX6ULL 一共包…

设计模式——行为型模式——策略模式(含实际业务使用示例、可拷贝直接运行)

目录 策略模式 定义 组成和UML图 代码示例 实际业务场景下策略模式的使用 策略模式优缺点 使用场景 JDK中使用策略模式示例 参考文档 策略模式 定义 策略模式定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以相互替换&#xff0c;且算法的变化…

PC端与bluetooth蓝牙虚拟串口通信

应该采用RFCOMM虚拟串口方式来进行通信&#xff0c;原理跟socket通信类似&#xff0c;不同的是使用的通信协议不同&#xff0c;本人结合相关的API&#xff0c;做了以下最简单的封装。 1、获取本地蓝牙设备与附近蓝牙设备信息 2、通信类 /* 通信类&#xff1a;只是对于客户端通…