这是我参与「第四届青训营 」笔记创作活动的第5天
贪心
1.题目描述
又是一年秋季时,陶陶家的苹果树结了 n 个果子。陶陶又跑去摘苹果,这次他有一个 a 公分的椅子。当他手够不着时,他会站到椅子上再试试。
这次与 NOIp2005 普及组第一题不同的是:陶陶之前搬凳子,力气只剩下 s 了。当然,每次摘苹果时都要用一定的力气。陶陶想知道在 s<0 之前最多能摘到多少个苹果。
现在已知 n 个苹果到达地上的高度 xi,椅子的高度 a,陶陶手伸直的最大长度 b,陶陶所剩的力气s,陶陶摘一个苹果需要的力气 yi,求陶陶最多能摘到多少个苹果。
输入格式
第 1 行:两个数 苹果数 n,力气 s。
第 2 行:两个数 椅子的高度 a,陶陶手伸直的最大长度 b。
第 3 行~第 3+n−1 行:每行两个数 苹果高度 xi,摘这个苹果需要的力气 yi。
输出格式
只有一个整数,表示陶陶最多能摘到的苹果数。
数据范围
对于 100% 的数据,n≤5000, a≤50, b≤200, s≤1000,xi≤280, yi≤100。
2.分析
在这个题里,所有苹果费力气也就是占背包空间不同,但是价值都是1。背包问题主要是为了解决拿得多却不一定价值最大,拿价值大的却可能装不下其他有价值的东西而使人陷入两难才被发明的算法。对于价值相同体积却不同的物品,我们每次只取体积最小的,就能在取得当前价值的情况下,最大化剩余空间,从而拿更多苹果,由此分析,运用贪心算法比动态规划算法更加好,是最优解。
3.证明
在能摘到苹果的前提下,我们每次先摘耗费力气最小的苹果,直到没有足够的力气去摘下一个苹果时,停止。因为此题并不涉及到苹果的价值,所有的苹果可以理解成是一样的,只有摘他们消耗的力气不同,所以显然我们先摘耗费最小的苹果是最优解。
4.代码
#include<iostream>
#include<algorithm>
using namespace std;
int n,s,a,b,x_,y_,can,rest,ans;
struct apple{
int xi,yi;
}ap[50005];
int cmp(apple x,apple y)
{
return x.yi<y.yi;
}
int main()
{
cin>>n>>s>>a>>b;
for(int i=1;i<=n;i++)
{
cin>>x_>>y_;
if(x_<=a+b)
{
can++;
ap[can].xi=x_;
ap[can].yi=y_;
}
}
sort(ap+1,ap+can+1,cmp);
rest=s;
ans=0;
for(int i=1;rest>=ap[i].yi&&i<=can;i++)
{
ans++;
rest-=ap[i].yi;
}
cout<<ans<<endl;
return 0;
}
5.复杂度分析
该题算法为典型的贪心算法,复杂度上界取决于排序。STL中sort的时间复杂度为O(nlogn),因此本题的时间复杂度为O(nlogn)