贪心策略:背包问题

贪心策略:背包问题

阿里巴巴与四十大盗——背包问题

在这里插入图片描述

有一天,阿里巴巴赶着一头毛驴上山砍柴。砍好柴准备下山时,远处突然出现一股烟尘,弥漫着直向上空飞扬,朝他这儿卷过来,而且越来越近。靠近以后,他才看清原来是一支马队,他们共有四十人,一个个年轻力壮、行动敏捷。一个首领模样的人背负沉重的鞍袋,从丛林中一直来到那个大石头跟前,喃喃地说道:“芝麻,开门吧!”随着那个头目的喊声,大石头前突然出现一道宽阔的门路,于是强盗们鱼贯而入。阿里巴巴待在树上观察他们,直到他们走得无影无踪之后,才从树上下来。他大声喊道:他小心翼翼地走了进去,一下子惊呆了,洞中堆满了财物,还有多得无法计数的金银珠宝,有的散堆在地区上,有的盛在皮袋中。突然看见这么多的金银财富,“芝麻,开门吧!”他的喊声刚落,洞门立刻打开了。阿里巴巴深信这肯定是一个强盗们数代经营、掠夺所积累起来的宝窟。为了让乡亲们开开眼界,见识一下这些宝物,他想一种宝物只拿一个,如果太重就用锤子凿开,但毛驴的运载能力是有限的,怎么才能用驴子运走最大价值的财宝分给穷人呢?阿里巴巴与四十大盗阿里巴巴陷入沉思中…

现在的山洞中,有n种宝物,每种宝物有一定重量w和相应的价值v,毛驴运载能力有限,只能运走m重量的宝物,一种宝物只能拿一样,宝物可以分割。那么怎么才能使毛驴运走宝物的价值最大呢?
思考一下,和上一题的海盗船不同的是,这题的宝物是可以分割的。因此,单纯选取价值最高或者重量最轻的宝物都不合适,而是单位重量内价值最高的宝物,即性价比最高的宝物。因此,来设计我们的算法吧。
首先,定义一个结构体

struct treasure
{
    double w; //宝物的重量
    double v; //宝物的价值
    double p; //宝物的性价比
}

在计算出每种宝物的性价比后,按照性价比从大到小(降序)排序,在装入背包时就从序列列首开始装入,直到达到最大装载量。
我们知道,使用sort函数可以完成排序的效果,但是怎么让sort函数知道按性价比来排序呢?因此我们需要定义一个函数参数,这个自定义的比较函数就可以使sort函数按照性价比来排序了
具体实现:

bool cmp(treasure a, treasure b)
{
	return a.p > b.p;
} //若a>b则return true反之则return false

这里为什么要用bool类型呢?首先,bool类型函数是指,函数的返回类型为bool型变量,即为true或者false。在这个cmp函数中,如果a.p > b.p就返回true,反之则返回false,这样就实现了一个比较器。sort函数中如加入了这样一个cmp参数,则函数就会自动按照性价比这一项的值进行降序排序了。在以后的编程中,多使用bool比较器+调用sort函数,熟练掌握后可以节省很多coding的时间。
然后思考如何可以达到“最贪心”呢?设计一个循环,判断一下就可以:

for (int i = 0; i < n; i++)
	{
		if (m > t[i].w) //若宝物重量小于最大承载量,接着装入宝物
		{
			m -= t[i].w;
			sum += t[i].w;

		}
		else    //若大于最大,则分割后装入
		{
			sum += m * t[i].p;
			break;
		}
	}

最后完整的源代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int M = 1000005;
struct treasure
{
	double w;
	double v;
	double p;
}t[M];
bool cmp(treasure a, treasure b)
{
	return a.p > b.p;
}
int main()
{
	int n;//宝物的数量
	double m;//最大装载量
	cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		cin >> t[i].w >> t[i].v; //循环输入宝物的重量以及价值
		t[i].p = t[i].v / t[i].w; //s[i].p就代表了每件宝物的性价比
	}
	sort(t, t + n, cmp);
	double sum = 0.0; //sum为已装载的宝物价值之和
	for (int i = 0; i < n; i++)
	{
		if (m > t[i].w)
		{
			m -= t[i].w;
			sum += t[i].w;

		}
		else
		{
			sum += m * t[i].p;
			break;
		}
	}
	cout << sum << endl;
	return 0;
}

最后,分析一下代码的时间复杂度与空间复杂度
排序算法时间复杂度O(nlogn),循环算法时间复杂度O(n),整体时间复杂度为O(n+nlogn);
由于需要存储每件宝物的性价比,因此空间复杂度为O(n)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值