背包问题【算法 07】

背包问题

请添加图片描述

背包问题是经典的计算机科学问题之一,涉及到如何在有限资源的约束下,选择最优的物品组合,以最大化收益。这个问题在现实中有广泛的应用,例如资源分配、物流调度和投资组合优化等。本文将详细介绍背包问题的定义、解决方法、常见变种,以及通过C语言的实现来帮助理解。

1. 背包问题简介

背包问题最早由丹麦数学家 Knuth 提出,其核心思想是:在一组物品中,每个物品都有一定的价值和重量,在背包的容量有限的前提下,选择哪些物品可以使得背包内物品的总价值最大化。

1.1 问题定义

背包问题可以表述为:给定 n 个物品,每个物品 i 有一个重量 w_i 和价值 v_i,在背包最大承重量 W 限制下,如何选择物品,使得装入背包的物品总重量不超过 W,且总价值最大。

公式化的定义如下:

  • 物品集合:{1, 2, ..., n}
  • 每个物品的重量:w_i
  • 每个物品的价值:v_i
  • 背包的容量:W

目标:在满足背包容量的前提下,最大化价值和:

max ∑ i = 1 n v i x i \text{max} \sum_{i=1}^n v_i x_i maxi=1nvixi
其中,x_i 表示第 i 个物品是否被选中,x_i = 1 表示选择,x_i = 0 表示不选择。

1.2 背包问题的类型

背包问题有多个变种,常见的类型包括:

  1. 0-1 背包问题:每个物品要么选择(1),要么不选择(0)。
  2. 完全背包问题:每个物品可以被选择多次。
  3. 分数背包问题:可以选择物品的一部分。

2. 0-1 背包问题

最经典的背包问题是 0-1 背包问题,即每个物品只能被选一次。此问题的解法包括动态规划(DP)和回溯法等。

2.1 动态规划解法

动态规划是一种自底向上的解决问题的方式,它可以有效地解决背包问题,避免暴力搜索带来的指数级时间复杂度。基本思想是构建一个二维数组 dp[i][w],表示前 i 个物品中能够装入重量为 w 的背包的最大价值。

2.1.1 状态转移方程

dp[i][w] 表示前 i 个物品能够放入容量为 w 的背包中的最大价值,则状态转移方程为:

d p [ i ] [ w ] = { d p [ i − 1 ] [ w ] , w < w i max ⁡ ( d p [ i − 1 ] [ w ] , d p [ i − 1 ] [ w − w i ] + v i ) , w ≥ w i dp[i][w] = \begin{cases} dp[i-1][w], & w < w_i \\ \max(dp[i-1][w], dp[i-1][w-w_i] + v_i), & w \geq w_i \end{cases} dp[i][w]={dp[i1][w],max(dp[i1][w],dp[i1][wwi]+vi),w<wiwwi
该方程表示如果当前物品 i 的重量超过背包剩余容量,则不能选择该物品;否则,我们可以选择不放入该物品或者放入该物品,取两者中的最大值。

2.2 动态规划算法实现

以下是 0-1 背包问题的 C 语言实现:

#include <stdio.h>// 定义最大物品数量和最大背包容量
#define MAX_ITEMS 100
#define MAX_WEIGHT 1000// 动态规划求解0-1背包问题
int knapsack(int n, int W, int weights[], int values[]) {int dp[MAX_ITEMS+1][MAX_WEIGHT+1] = {0};// 遍历每个物品for (int i = 1; i <= n; i++) {for (int w = W; w >= weights[i-1]; w--) {dp[i][w] = dp[i-1][w];if (w >= weights[i-1]) {dp[i][w] = (dp[i-1][w] > dp[i-1][w - weights[i-1]] + values[i-1]) ? dp[i-1][w] : (dp[i-1][w - weights[i-1]] + values[i-1]);}}}return dp[n][W];
}int main() {int n = 5;  // 物品数量int W = 10; // 背包容量int weights[] = {2, 2, 6, 5, 4};  // 每个物品的重量int values[] = {6, 3, 5, 4, 6};   // 每个物品的价值int maxValue = knapsack(n, W, weights, values);printf("背包可以装入的最大价值为: %d\n", maxValue);return 0;
}

2.3 案例分析

假设有5个物品,重量分别为 {2, 2, 6, 5, 4},价值分别为 {6, 3, 5, 4, 6},背包容量为 10

通过动态规划方法,得到的最大价值为 15。这是通过选择第 1、第 2 和第 5 个物品实现的,它们的总重量为 2+2+4=8,总价值为 6+3+6=15

3. 完全背包问题

在完全背包问题中,每个物品可以选择多次。这与 0-1 背包问题的区别在于,状态转移方程发生了变化,因而求解方法也有所不同。

3.1 状态转移方程

对于完全背包问题,状态转移方程为:

d p [ i ] [ w ] = max ⁡ ( d p [ i − 1 ] [ w ] , d p [ i ] [ w − w i ] + v i ) dp[i][w] = \max(dp[i-1][w], dp[i][w-w_i] + v_i) dp[i][w]=max(dp[i1][w],dp[i][wwi]+vi)
与 0-1 背包不同,选择当前物品时,需要考虑放入多次的情况。

3.2 完全背包问题的C语言实现

#include <stdio.h>int knapsack_complete(int n, int W, int weights[], int values[]) {int dp[MAX_WEIGHT+1] = {0};for (int i = 0; i < n; i++) {for (int w = weights[i]; w <= W; w++) {dp[w] = (dp[w] > dp[w - weights[i]] + values[i]) ? dp[w] : dp[w - weights[i]] + values[i];}}return dp[W];
}int main() {int n = 5;int W = 10;int weights[] = {2, 2, 6, 5, 4};int values[] = {6, 3, 5, 4, 6};int maxValue = knapsack_complete(n, W, weights, values);printf("完全背包可以装入的最大价值为: %d\n", maxValue);return 0;
}

3.3 案例分析

在同样的物品和背包容量情况下,完全背包的最大价值是 18,因为在完全背包中,可以选择物品 15 多次,从而获得更高的价值。

4. 分数背包问题

分数背包问题允许将物品分割开来,也就是说可以选择物品的一部分。通常使用贪心算法解决该问题,依据单位重量的价值(价值/重量)对物品进行排序,然后依次选择单位价值最高的物品直到背包满为止。

4.1 分数背包问题的案例分析

在分数背包问题中,物品可以被部分选择,这与 0-1 背包和完全背包不同。例如,假设有以下 3 个物品:

  • 物品 1:重量 10,价值 60
  • 物品 2:重量 20,价值 100
  • 物品 3:重量 30,价值 120

背包的容量为 50。我们可以计算每个物品的单位重量价值,即 value/weight 比率:

  • 物品 1:60/10 = 6
  • 物品 2:100/20 = 5
  • 物品 3:120/30 = 4

根据贪心算法的思想,应该优先选择单位价值最高的物品。具体过程如下:

  1. 选择物品 1(单位价值最高,6),将其全部放入背包。此时,背包剩余容量为 50 - 10 = 40,价值为 60
  2. 选择物品 2(单位价值次高,5),将其全部放入背包。此时,背包剩余容量为 40 - 20 = 20,价值增加为 60 + 100 = 160
  3. 选择物品 3(单位价值最低,4),但此时背包只剩下 20 的空间,因此只能选择物品 3 的一部分,价值为 120 * (20/30) = 80

因此,最终的最大价值为 60 + 100 + 80 = 240

4.2 分数背包问题的 C 语言实现

以下是分数背包问题的 C 语言实现:

#include <stdio.h>
#include <stdlib.h>typedef struct {int weight;int value;double ratio;
} Item;// 比较函数,用于根据单位价值对物品排序
int cmp(const void* a, const void* b) {return ((Item*)b)->ratio > ((Item*)a)->ratio ? 1 : -1;
}// 贪心算法解决分数背包问题
double fractional_knapsack(int n, int W, Item items[]) {// 根据单位价值排序qsort(items, n, sizeof(Item), cmp);double maxValue = 0.0;// 贪心地选择物品for (int i = 0; i < n && W > 0; i++) {if (W >= items[i].weight) {W -= items[i].weight;maxValue += items[i].value;} else {maxValue += items[i].value * ((double)W / items[i].weight);W = 0;}}return maxValue;
}int main() {int n = 3;  // 物品数量int W = 50; // 背包容量Item items[] = {{10, 60, 6.0},{20, 100, 5.0},{30, 120, 4.0}};double maxValue = fractional_knapsack(n, W, items);printf("分数背包可以获得的最大价值为: %.2f\n", maxValue);return 0;
}

4.3 分析与总结

通过贪心算法,我们可以有效解决分数背包问题。该算法的时间复杂度主要由排序决定,为 O(n log n),而解决过程为 O(n)。与动态规划相比,贪心算法的效率更高,但它只能用于分数背包问题,不能用于 0-1 背包问题。

5. 不同背包问题的比较

问题类型可选物品算法类型时间复杂度备注
0-1 背包问题每个物品只能选择一次动态规划O(nW)经典问题
完全背包问题每个物品可以选择多次动态规划O(nW)物品可多次选择
分数背包问题物品可以部分选择贪心算法O(n log n)需要排序

6. 背包问题的现实应用

背包问题在许多实际应用中有广泛的应用,例如:

  1. 资源分配问题:在有限的资源下,如何分配资源以最大化收益。
  2. 物流调度问题:如何在有限的运输空间内安排货物的装载,使得运输效益最大化。
  3. 投资组合问题:如何在有限的资金下,选择合适的投资组合以最大化收益。

背包问题的灵活性使得它可以应用于各种优化问题中,不仅仅局限于物理背包的装载问题。

7. 总结

背包问题作为组合优化中的经典问题,有多种变体和解决方法。本文详细介绍了 0-1 背包问题、完全背包问题和分数背包问题的概念、算法及实现,并通过案例分析加深对这些问题的理解。通过不同的解法,解决了物品选择的最大价值问题,这种优化思想在现实中有广泛的应用价值。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iphone问题笔记

拼音打字显示一些不相干的词 原因&#xff1a;开启了自动改正&#xff0c;傻逼iphone总以为你打错了。 计算器没有退格键&#xff1f; 解决方法&#xff1a;按住数字往右滑是退格。 关机重启必须去设置里&#xff1f; 连按五次锁屏可以选择关机。

如何选择适合自己的开放式耳机?五款实力出众爆款安利!

开放式耳机以其不侵入耳道的设计&#xff0c;为耳朵提供了更轻的负担&#xff0c;同时保护了耳道健康&#xff0c;这与传统的头戴式或入耳式耳机相比&#xff0c;在长时间佩戴时更能减少不适感。市场上的开放式耳机种类繁多&#xff0c;要找到一款真正满意的产品可能有些困难。…

文件—python

一、文件编码 对于同一份文件&#xff0c;人的视角和计算机的视角是不相同的&#xff0c;人看到的是文字&#xff0c;计算机看到的0和1组成的编码。因为计算机只能识别0和1&#xff0c;无法直接识别文字&#xff0c;那我们是如何在电脑上看到文字的呢&#xff1f; 计算机按照一…

【逐行注释】MATLAB下的IMM-EKF代码

IMM-EKF 基于EKF的多模型交互。以CV和CT两个模型进行交互&#xff0c;这里对代码进行逐行注释。 注释较多&#xff0c;个人理解的时候如果有误&#xff0c;欢迎指正。 每一行都有注释&#xff1a; 模型概况 二维平面上的运动模型&#xff0c;由CV和CT构成&#xff0c;基于…

C++:vector篇

前言&#xff1a; 本篇仅介绍vector中常用的函数接口&#xff0c;如果需要详细的请到官网查看。 vector是一种动态数组&#xff0c;能够自动调整大小。与数组类似&#xff0c;vector使用连续内存来存储元素&#xff0c;允许高效访问&#xff0c;但可以动态增加容量。为了应对容…

达梦数据库的系统视图v$tablespace

达梦数据库的系统视图v$tablespace 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$TABLESPACE 提供了有关数据库中的表空间&#xff08;Tablespace&#xff09;信息。这些信息对于管理数据库存储和优化性能非常关键。表空间是数据库逻辑存储结构的一个层次…

12、stm32通过dht11读取温湿度

一、配置 二、代码 dht11.c /** dht11.c** Created on: Aug 19, 2024* Author: Administrator*/#include "main.h" #include "tim.h" #include "usart.h" #include "gpio.h" /**TIM3定时器实现us级延时*/ void Delay_us(uint16…

Midjourney提示词-动物系列-65

A super cute little anthropomorphic,sheep of the Chinese Zodiac, wearing berets ,in a Hanfu in red style,standing, eyes,cute tail,super realistic,super detail,luxurious,elegant,Unreal Engine,octane render, 8K,VRAY super realistic Pixar Style, Tiny cute…

[matlab]MATLAB实现MLP多层感知机minist手写识别预测

【测试环境】 matlab2023a 【源码文件截图】 【实现部分代码】 mlp_test.m %% MLP 2-layer to test XOR clear; clc;Mode MNIST %Mode XORif (strcmp(Mode,MNIST))% Load the digits into workspace (MNIST Test, from% http://yann.lecun.com/exdb/mnist/)num_train 100…

为什么要构建自己的 AI 代理库

上个月&#xff0c;我开始深入研究 AI 代理的世界。在探索这个领域时&#xff0c;我突然有了灵感&#xff1a;从现在开始我要研究 AI 代理。 最近&#xff0c;我一直在思考第二点。既然有很多可用的选项&#xff0c;为什么还要开发自己的 AI 代理库呢&#xff1f; 经过一番思…

SCI论文系统各阶段状态含义,一文带你全面掌握!告别投稿小白!

知识小站 SCI&#xff08;Science Citation Index&#xff0c;科学引文索引&#xff09;是由美国科学信息研究所&#xff08;Institute for Scientific Information, ISI&#xff09;创建的一个引文数据库。它收录了全球各学科领域中最具影响力的学术期刊&#xff0c;涵盖自然…

PyTorch深度学习模型训练流程的python实现:回归

回归的流程与分类基本一致&#xff0c;只需要把评估指标改动一下就行。回归输出的是损失曲线、R^2曲线、训练集预测值与真实值折线图、测试集预测值散点图与真实值折线图。输出效果如下&#xff1a; 注意&#xff1a;预测值与真实值图像处理为按真实值排序&#xff0c;图中呈现…

OCR识别行驶证(阿里云和百度云)

OCR识别行驶证(阿里云和百度云) 一、使用场景 1、通过识别行驶证&#xff0c;获取相关汽车信息&#xff0c;替代手输 二、效果图 三、代码部分&#xff1a; 1、阿里云OCR 1.1、控制层 PostMapping("/ocrCard") public JSONObject ocrCard(RequestPart("fi…

快速入门:使用Python构建学生成绩管理应用

前言 诸位观众&#xff0c;本学期我有幸学习了Python编程课程。随着课程的结束&#xff0c;授课教师布置了一项任务&#xff0c;要求我们开发一个学生信息管理系统。基于老师的要求&#xff0c;我个人独立完成了这项任务。今天&#xff0c;我希望将这个简易的程序分享给大家&a…

【数字三角形】

题目 代码 #include <bits/stdc.h> using namespace std;const int N 510; int f[N][N]; int a[N][N]; int main() {int n;cin >> n;for(int i 1; i < n; i){for(int j 1; j < i; j){cin >> a[i][j];if(i 1 && j 1) f[i][j] a[i][j];el…

ORCAD Capture CIS 打开原理图总是卡住

原因&#xff1a;ORCAD自动进行了DRC检查。要打开的原理图中footprint未指定footprint路径。 修改&#xff1a;1、第一种方法&#xff1a;指定footprint路径 2、第二种方法&#xff1a;关闭在线DRC检查

钢包智慧管理平台

钢包智慧管理平台基于海康、大华视频监控&#xff0c;实现对钢包的全动态管理&#xff0c;实时检测钢包的温度数据变化&#xff0c;也可以随时查询时间区间内的钢包温度数据变化。 平台基于springboot vue前后台分离技术开发&#xff0c;视频基于zlmedia的转码拉流。实现了视频…

STM32————SPI硬件外设实现读写

首先是理论知识&#xff1a; 常用8位数据帧、高位先行 SPI的时钟由PCLK内部时钟分频得来&#xff0c;最大可到36MHz 精简为半双工就是去掉一根数据线后&#xff0c;用剩下的一根作为发送/接收数据&#xff1b;单工就是去掉接收线&#xff0c;只用发送线进行发送数据&#xf…

揭秘CAAC、AOPA、ALPA、ASFC和UTC无人机执照的差别及实用价值

CAAC、AOPA、ALPA、ASFC和UTC无人机执照各有其独特的差别及实用价值&#xff0c;以下是针对这些执照的详细解析&#xff1a; 一、CAAC无人机执照 颁发机构&#xff1a;中国民用航空局&#xff08;CAAC&#xff09; 差别&#xff1a; - 权威性&#xff1a;CAAC无人机执照是目…

Java面试题--JVM大厂篇之JVM 大厂面试题及答案解析(2)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到我的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而我的博客&…