【贪心算法】一般背包问题(C++)

一、关于一般背包问题

1. 问题描述:

  • 设有n个物品和一个背包,物品i的重量为wi,价值为vi,背包的容量为C。若将物品i的xi部分(1≤i≤n,0≤xi≤1)装入背包,则具有价值为vixi
  • 目的是找到一个方案,使放入背包的物品总价值最高
  • 与0-1背包问题类似,不同的是在选择物品 i 装入背包时,可以选择物品 i 的一部分,而不一定要全部装入背包。

2. 问题分析:

  • 思考
    • 贪心算法总是作出在当前看来最好的选择,或者说在某种意义上的局部最优选择。
    • 因此,在考虑放入物品时,应当选择所有(剩余)物品中价值比(*单位重量的价值)最高的一个放入,然后考虑背包(剩余)容量,选择放入物品的多少部分。
    • 最终找到一个n元向量(x1, …, xn)(0≤xi≤1),使得 ∑ i = 1 n w i x i ≤ c \sum_{i=1}^n w_ix_i \leq c i=1nwixic,且 m a x ∑ i = 1 n v i x i max\sum_{i=1}^n v_ix_i maxi=1nvixi
  • 得出算法思路
    1. 各物体按单位价值由高到低排序;
    2. 取价值最高者放入背包;
    3. 计算背包剩余空间;
    4. 在剩余物体中取价值最高者放入背包;
    5. 重复2, 3, 4步,直到背包剩余容量为0或物品全部装入背包为止。
  • 该算法的主要时间在于:将各种物品依其单位重量的价值从大到小排序。

二、算法实现

1. 贪心算法

//一般背包问题 贪心算法
#include <iostream> 
using namespace std;

void knapsack(int n, double M, double v[], double w[], double x[]);	// 背包算法

int main()
{
	cout << "一般背包问题的贪心算法\n\n";

	const int n = 4;	// 物品个数
	double C = 50;		// 背包所能容纳的重量
	double x[n + 1];	// 物品选择向量
	double w[] = { 0,10,20,30,40 };		// 下标从1开始,物品i的重量(已按单位价值减序排序)
	double v[] = { 0,60,100,120,120 };	// 下标从1开始,物品i的价值(已按单位价值减序排序)

	cout << "背包所能容纳的重量为:" << C << endl;
	cout << "物品的重量和价值分别为:" << endl;
	for (int i = 1; i <= n; i++)
		cout << "[" << i << "]:(" << w[i] << "," << v[i] << ")" << endl;

	knapsack(n, C, w, v, x);

	cout << "\n物品选择向量为:(";
	for (int i = 1; i <= n; i++)
	{
		cout << x[i];
		if (i + 1 <= n)
			cout << ",";
		else
			cout << ")\n";
	}

	return 0;
}

void knapsack(int n, double C, double w[], double v[], double x[])
{
	// 对物品按单位价值排序
	// sort(n, w, v);

	// 所有元素设为0,背包初始状态(没有装入任何物品)
	memset(x, 0, sizeof(double) * (n + 1));

	int i;			// 第 i 个物品
	double c = C;	// 背包剩余容量

	// 物品i整件被装下,x[i]=1
	for (i = 1;i <= n;i++)
	{
		if (w[i] > c)
			break;
		x[i] = 1;
		c -= w[i];
	}

	// 物品i只有部分被装下,x[i] = c / w[i];
	if (i <= n)
		x[i] = c / w[i];
}

2. 运行结果展示

运行截图
·

三、友情链接~


最后,非常欢迎大家来讨论指正哦!

  • 7
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值