使用 C++ 的分数背包

2023-11-12

在本文中,我们将学习使用 C++ 解决分数背包问题。我们将从查看问题陈述开始,然后转向解决方案。该问题是许多流行的经典问题之一。它与它的兄弟 0-1 背包有很大不同0-N背包。这是一种贪心算法,另外两种是动态规划算法。

什么是分数背包?

您将获得某些物品的重量和价格清单以及一定容量(例如 W)的袋子/背包。您的任务是以这样的方式填充这个袋子,使您在这个袋子中携带的所有物品的总价格最大对于所有配置。您可以收集任何对象的整体或部分。

分数背包算法

好吧,我们来看看解决这个问题的算法。由于我们将对此问题实现贪婪解决方案,因此下面是贪婪算法的简要描述。

什么是贪心算法?

在这些算法中,我们的目标是在每一步实现局部最大值/最小值,以便最终实现全局最大值/最小值。也就是说,我们最大化/最小化每个子问题的答案,从而得出整个问题的最大/最小答案。

Note:你将要做出的贪婪的选择一定是一个安全的举动。

Safe Move:如果该初始移动存在可靠的最佳答案,则该移动称为安全移动。

使用贪婪算法的策略

以下是开发完美贪心算法时应遵循的步骤。

  • 做出贪心的选择
  • Prove它是一个安全移动这样你就不会编写代码并最终发现这不是一个可行的选择。这个特定的步骤是贪心算法最重要的步骤。
  • 减少到更小的问题
  • 解决所有较小的问题。
General Strategy For Greedy Algorithms
General Strategy For Greedy Algorithms

伪代码

现在我们将逐步介绍背包算法。

  • 按价值/重量比的降序对物品进行排序。仅此一步就降低了从其中选择最佳项目的时间复杂度O(N) to O(log2N).
  • 现在我们开始通过运行来选择对象for 循环从 i = 0 到 i = N
  • Lemma: There exists an optimal solution that uses as much as possible of an item with the maximum value per unit of weight.
    • 证明:尝试用不同的选择标准填充背包,你得到的总价值总是小于最大可能值。

下面所附的例子证明我们的引理是正确的。

Safe Move Proof
Safe Move Proof
  • 现在,如果价值/重量比最大的物品的尺寸适合背包,则将其全部取出。否则,取其中最大可能的分数。
  • Reduce the capacity of the bag by the weight of the item taken.
    • 如果整个项目都被拿走,那么:capacity = capacity - weight[this_item].
    • 否则,由于背包已满,容量变为0。
  • Add the value of the fraction of this item taken to the total value.
    • 如果整个项目被拿走:total_value += value[this_item]
    • 否则,value += fraction_of_weight_taken * value[this_item].
  • 如果容量变为0,则跳出循环。

伪代码的整体结构变为:

Fractional Knapsack Pseudocode
Fractional Knapsack Pseudocode

演示分数背包的 C++ 程序

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

// this custom comparator function will allow
// us to compare our vector based on the
// ratio of values to weights
bool compare(pair <float, int> p1, pair <float, int> p2)
{
	return p1.first > p2.first;
}

int fractional_knapsack(vector <int> weights, vector <int> values, int capacity)
{
	int len = weights.size();
	int total_value = 0;

	// vector to store the items based on their value/weight ratios
	vector <pair <float, int>> ratio(len, make_pair(0.0, 0));

	for(int i = 0; i < len; i++)
		ratio[i] = make_pair(values[i]/weights[i], i);

	// now sort the ratios in non-increasing order
	// for this purpose, we will use our custom
	// comparator function
	sort(ratio.begin(), ratio.end(), compare);

	// start selecting the items
	for(int i = 0; i < len; i++)
	{
		if(capacity == 0)
			break;

		int index = ratio[i].second;

		if(weights[index] <= capacity)
		{
			// we item can fit into the knapsack
			// hence take the whole of it
			capacity -= weights[index];

			// add the value of this item to the
			// final answer
			total_value += values[index];
		}
		else
		{
			// this item doesn't fit into the bag
			// and thus we take a fraction of it
			int value_to_consider = values[index] * (float(capacity)/float(weights[index]));
			total_value += value_to_consider;
			capacity = 0;
		}
	}

	return total_value;
}

int main()
{
	cout << "Enter the weights of the items, press -1 to stop" << endl;

	vector <int> weights;

	while(true)
	{
		int weight;
		cin >> weight;

		if(weight == -1)
			break;

		weights.push_back(weight);
	}

	cout << "Enter the values of each item, press -1 to stop" << endl;
	
	vector <int> values;

	while(true)
	{
		int value;
		cin >> value;

		if(value == -1)
			break;

		values.push_back(value);
	}

	cout << "Enter the capacity of the knapsack" << endl;

	int capacity;
	cin >> capacity;

	cout << "The maximum value possible based on current list is: " << fractional_knapsack(weights, values, capacity) << endl;
}
Fractional Knapsack Algorithm Code
Fractional Knapsack Algorithm Code
Driver Function
Driver Function

Output

Fractional Knapsack Output
Fractional Knapsack Output

结论

分数背包是一种贪婪算法,在本文中,我们研究了它的实现。我们简要了解了贪婪算法,然后讨论了分数背包算法的伪代码。我们证明了我们的贪婪选择是安全的,最后,我们编写了一个 C++ 程序来演示这个解决方案。这个概念的总体时间复杂度是:O(Nlog2N)。今天的内容就到这里,感谢您的阅读。

进一步阅读

如果你想了解更多关于背包和其他贪心算法的知识,可以参考以下网站。

https://brilliant.org/wiki/greedy-algorithm

https://en.wikipedia.org/wiki/Knapsack_problem

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C++ 的分数背包 的相关文章

  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 重载<<的返回值

    include
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new

随机推荐

  • 获取R中的行数和列数

    各位读者大家好 在本文中 我们将重点讨论 R 中的行和列的概念 即R编程中获取对象的行数和列数 详细 那么 让我们开始吧 Be it a matrix or a 数据框 我们按照行和列来处理数据 在数据分析领域 尤其是统计分析 我们需要了解
  • 如何在 CentOS、Rocky Linux、RHEL 和 Fedora 上安装 Java

    介绍 本教程将向您展示如何在基于 RPM 的 Linux 发行版的当前版本上安装 Java Red Hat Enterprise Linux CentOS Fedora 和 Rocky Linux Java 是一种流行的编程语言和软件平台
  • 如何在 Ubuntu 14.04 上使用 Nginx 安装 WordPress

    介绍 WordPress 是世界上最流行的 CMS 内容管理系统 它使您可以轻松启动并运行您的网站或博客 安装后 您可以在简单的 Web 界面中管理几乎所有内容 在本指南中 我们将介绍如何在 Ubuntu 14 04 服务器上安装 Word
  • 如何使用 Nmap 和 Tcpdump 测试您的防火墙配置

    介绍 为您的基础设施设置防火墙是为您的服务提供安全性的好方法 一旦您制定了满意的策略 下一步就是测试您的防火墙规则 重要的是要充分了解您的防火墙规则是否按照您的想法进行 并了解您的基础设施在外界看来是什么样子 在本指南中 我们将介绍一些可用
  • Linux 终端简介

    介绍 本教程是 Linux 基础知识系列的第一篇 涵盖终端 Linux 命令行和执行命令的入门知识 如果您是 Linux 新手 您将需要熟悉终端 因为它是与 Linux 服务器交互的标准方式 如果您想充分利用本教程 您将需要连接和使用 Li
  • 最小堆二叉树

    A Min Heap二叉树是二叉树 其中根节点具有树中的最小键 上述定义对于树中的所有子树都适用 这被称为最小堆属性 除了最后两层之外 几乎每个节点都必须有两个子节点 也就是说 除了最后两层之外 这几乎是一个完整的二叉树 由于上述两个属性成
  • 在 Python 3 中使用循环时如何使用 Break、Continue 和 Pass 语句

    介绍 Using for 循环 and while 循环Python 允许您以有效的方式自动化和重复任务 但有时 外部因素可能会影响程序的运行方式 发生这种情况时 您可能希望程序完全退出循环 在继续之前跳过循环的一部分 或者忽略该外部因素
  • 休眠教程

    最近写了很多hibernate教程 休眠是当前市场上最好的Java ORM工具之一 所以这篇文章就像是所有 hibernate 教程和示例文章的索引 您可以依次浏览这些 hibernate 教程 从头开始学习 hibernate 我很可能会
  • Java 中的线程安全

    Java中的线程安全是一个非常重要的话题 Java使用Java线程提供多线程环境支持 我们知道从同一个对象创建的多个线程共享对象变量 这可能会导致数据不一致当线程用于读取和更新共享数据时 线程安全 The reason for data i
  • 如何使用 Ansible 角色抽象您的基础设施环境

    介绍 Ansible 是一种配置管理工具 旨在为管理员和运营团队自动控制服务器 借助 Ansible 您可以使用单个中央服务器来控制和配置许多不同的远程系统 仅使用 SSH 和 Python 作为要求 Ansible 根据任务定义在其管理的
  • 如何在 CentOS 6 上使用 fail2ban 保护 SSH

    Status 已弃用 本文介绍不再受支持的 CentOS 版本 如果您当前运行的服务器运行 CentOS 6 我们强烈建议您升级或迁移到受支持的 CentOS 版本 Reason CentOS 6 于 2020 年 11 月 30 日达到生
  • 如何监控 DigitalOcean Droplet 上的 CPU 使用情况

    介绍 假设您的网站或应用程序比平时更慢 你如何开始调查这个问题 导致应用程序缓慢的原因有很多 但有时是因为服务器的 CPU 已满 本指南将帮助您了解您是否属于这种情况 我们将首先了解 Linux 服务器上两个最常引用的资源使用指标 CPU利
  • 如何在 Python 中将字符串转换为浮点数

    介绍 在这篇文章中 我们将使用Pythonfloat 函数将字符串转换为浮点数 我们还将使用Python的str 函数将浮点数转换为字符串 在使用数据类型进行计算和串联之前正确转换数据类型非常重要 以防止运行时错误 先决条件 为了完成本教程
  • 机器学习简介

    介绍 机器学习是人工智能 AI 的一个子领域 机器学习的目标通常是理解数据的结构并将该数据拟合到人们可以理解和利用的模型中 尽管机器学习是计算机科学的一个领域 但它与传统的计算方法不同 在传统计算中 算法是计算机用来计算或解决问题的显式编程
  • 如何将路由解析器与 Angular 路由器一起使用

    介绍 处理从 API 检索和显示数据的一种方法是将用户路由到组件 然后在该组件的ngOnInit钩子调用服务中的方法来获取必要的数据 在获取数据时 组件也许可以显示加载指示器 还有另一种方法可以使用所谓的route resolver 它允许
  • 如何在 Ubuntu 14.04 上安装 LAMP [快速入门]

    介绍 LAMP 堆栈 Linux Apache MySQL PHP 是一组开源软件 通常安装在一起以使服务器能够托管动态 PHP 网站和 Web 应用程序 本指南包括在 Ubuntu 14 04 上的单个服务器上设置 LAMP 堆栈的步骤
  • Python 中的引导采样

    这是关于 Python 中的 Bootstrap 采样的教程 在本教程中 我们将了解什么是引导 然后了解如何实现它 让我们开始吧 什么是引导抽样 引导抽样的定义如下 在统计学中 引导抽样是一种方法 涉及从数据源中重复抽取样本数据并进行替换
  • 如何在 Ubuntu 14.04 上为多个 Apache 虚拟主机设置 Let's Encrypt 证书

    介绍 SSL 证书在 Web 服务器内用于加密服务器和客户端之间的流量 为访问您的应用程序的用户提供额外的安全性 Let s Encrypt 提供了一种免费获取和安装受信任证书的简单方法 本教程将向您展示如何设置 TLS SSL 证书让我们
  • 如何在 Ubuntu 18.04 上安装 Go

    介绍 Go是 Google 开发的一种现代编程语言 它在许多应用程序和许多公司中越来越受欢迎 并提供了一组强大的库 本教程将引导您下载和安装最新版本的 Go 本文发布时为 Go 1 10 以及构建一个简单的 Hello World 应用程序
  • 使用 C++ 的分数背包

    在本文中 我们将学习使用 C 解决分数背包问题 我们将从查看问题陈述开始 然后转向解决方案 该问题是许多流行的经典问题之一 它与它的兄弟 0 1 背包有很大不同0 N背包 这是一种贪心算法 另外两种是动态规划算法 什么是分数背包 您将获得某