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