解法:
按礼物的价值/重量比从大到小依次选取礼物,对选
取的礼物尽可能多地装,直到达到总重量w
复杂度: O(nlogn)
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
struct s
{
int a;
int b;
double x;
};
struct rule
{
bool operator ()(const s & s1,const s & s2)
{
return s1.x > s2.x;
}
};
int main()
{
scanf("%d%d",&n,&m);
s h[10000];
for( int i=0; i<n; i++)
{
scanf("%d%d",&h[i].a,&h[i].b);
h[i].x=h[i].a/h[i].b;
}
sort(h,h+n,rule());
double num=0,mum=0;
for(int i=0; i<n; i++)
{
if(m-mum>=h[i].b)
{
num+=h[i].a;
mum+=h[i].b;
}
else
{num+=(m-mum)*h[i].x;
break;
}
}
printf("%.1lf",num);
return 0;
}
下面是一种比较好的写法:
#include<cstdio>
#include<algorithm>
using namespace std;
const double eps = 1e-6;
struct Candy
{
int v;
int w;
bool operator < (const Candy & c)
{
return double(v)/w - double(c.v)/c.w > eps;
}
} candies[110];
int main()
{
int n,w;
scanf("%d%d",&n,&w);
for(int i = 0; i < n; ++i)
scanf("%d%d", &candies[i].v, &candies[i].w);
sort (candies,candies+n);
int totalW = 0;
double totalV = 0;
for(int i = 0; i < n; ++i)
{
if( totalW + candies[i].w <= w)
{
totalW += candies[i].w;
totalV += candies[i].v;
}
else
{
totalV += candies[i].v *
double(w-totalW)/candies[i].w;
break;
}
}
printf("%.1f",totalV);
return 0;
}
最后贪心重在证明
证明: 替换法。对于用非此法选取的最大价值糖果箱序列, 可以将其按价值/重量比从大到小排序后得到: 序列1:a1, a2 …
用序列1和按上述解法选取的序列2依次进行比较: 序列2:b1, b2 …
价值/重量比相同的若干箱糖果,可以合并成一箱,所以两个序列中元素都不重复 对于发现的第一个 ai != bi ,则必有:ai< bi
则在序列1中,用 bi 这种糖果,替代若干重量的 ai 这种糖果,则会使得序列1的总价 值增加,这和序列1是价值最大的取法矛盾
所以:序列1 = 序列2 (序列2不可能是序列1的一个前缀且比序列1短)
每一步行动总是按某种指标选取最优的操作来进行, 该指标只看眼前,并不考虑以后可能造成的影响。
贪心算法需要证明其正确性。 “圣诞老人礼物”题,若糖果只能整箱拿,则贪心法错误。
每一步行动总是按某种指标选取最优的操作来进行, 该指标只看眼前,并不考虑以后可能造成的影响。
贪心算法需要证明其正确性。
“圣诞老人礼物”题,若糖果只能整箱拿,则贪心法错误。
考虑下面例子:
3个箱子(8,6) (5,5) (5,5),雪橇总容量10