贪心算法例题讲解(2)
文章首发于:My Blog 欢迎大佬们前来逛逛
P1478 陶陶摘苹果(升级版)
直接将摘苹果所需要的力气按照从到大排序即可。
那么这样,摘的最轻松的苹果不摘白不摘,摘它这么轻松,干嘛不摘。
如果遇到了 足够力气摘得苹果,但是高度够不到,不摘不就好了,又不损失什么,反正我们是按照花费得力气排序的。
//TODO: Write code here int n,m; int a,b; const int N=1e5+10; int nums[N]; struct Node { int x,y; }apple[N]; bool comp(Node a,Node b) { if (a.y<b.y) return true; return false; } signed main() { cin>>n>>m>>a>>b; for (int i=1;i<=n;i++) { cin>>apple[i].x>>apple[i].y; } sort(apple+1,apple+1+n,comp); int sum=a+b; int ans=0; for (int i=1;i<=n;i++) { if (apple[i].x<=sum && apple[i].y<=m) { m-=apple[i].y; ans+=1; } } cout<<ans; #define one 1 return 0; }
P5019 [NOIP2018 提高组] 铺设道路
这是一种很重要的贪心问题!
处理连续的一段区间,让这个区间里的数字做一些操作。
常见的这类问题有:
这段区间的每个值都减少 1,直到为0为止,操作的区间的数字不能是0
发牌,每次从区间中发出一些牌,只能连续的发,不能跳跃,求出发完所有牌的最小发牌次数
总结为一类问题:求 操作每个元素都不为零 的一段区间,使得整个序列所有的元素都为0的最少操作次数,每次操作只能操作一段区间
回到这题:贪心算法如何求解?
可以注意到如果第 i 个的元素大于第 i-1 个位置的元素,则对 i 和 i-1 位置的操作次数一定是 nums[i] 减去 nums[i-1]
即:
if (nums[i]>nums[i-1]) ans+=nums[i]-nums[i-1]
注意到 : i 位置的元素一定比 i-1 位置的元素大,因此无论如何你一定要 对 i 位置的元素操作为0,所以对 i 位置的元素操作相当于免费操作了 i -1 位置的元素。
类似于如下:
4 3 2 5 3 5
4 3 0 2 3 5
4 3 0 2 1 3
最后遍历完整个序列之后,ans+ =nums[1]
0 0 0 0 0
//TODO: Write code here int n,m; const int N=1e5+10; int nums[N]; signed main() { cin>>n; for (int i=1;i<=n;i++) { cin>>nums[i]; } int ans=0; for (int i=1;i<n;i++) { if (nums[i]<nums[i+1]) { ans+=nums[i+1]-nums[i]; } } cout<<ans+nums[1]; #define one 1 return 0; }
P1208 [USACO1.3]混合牛奶 Mixing Milk
P1208 [USACO1.3]混合牛奶 Mixing Milk
贪心思路:直接按照牛奶的单价进行排序,如果单价有一样的,则按照 量多的在前面
很明显,量多的并且单价还便宜的一定是最优的。
因此直接AC:
//TODO: Write code here int n,m; const int N=2e6+10; int nums[N]; struct Node { int a,p; }node[N]; bool comp(Node a,Node b) { if (a.a<b.a) return true; else if (a.a==b.a) return a.p>b.p; return false; } signed main() { cin>>n>>m; for (int i=1;i<=m;i++) { cin>>node[i].a>>node[i].p; } sort(node+1,node+1+m,comp); int ans=0; for (int i=1;i<=m;i++) { if (n<=0) break; if (node[i].p<=n) { n-=node[i].p;//购买了p个 ans+=node[i].a*node[i].p;//p种的总成本 } else { ans+=node[i].a*n; break; } } cout<<ans; #define one 1 return 0; }
P1094 [NOIP2007 普及组] 纪念品分组
很典型的贪心问题:要使得组的数量尽可能少,则组内两个纪念品一定是一个尽量可能小,一个尽量可能大
这样才满足一个组的利用率达到最高
即寻找 小于等于最大价值之和的 能够提供最大价值的两个纪念品
则我们单价进行排序,左边尽量小 和 右边尽量大 的在 满足不大于最大价值限制的情况下,要组成一组,
如果:
if (s左 + s右 > limit) { I右-- } else { I左++ I右-- }
则这样遍历完一遍后,整个序列中满足条件的两个最优的纪念品就分好了,则其他的就只能单独一组!
贪心算法的证明, 某大佬的解答:
题解 P1094 【纪念品分组】 - heidoudou 的博客 - 洛谷博客 (luogu.com.cn)
//TODO: Write code here int n,m; const int N=1e5+10; int nums[N]; bool fg[N]; signed main() { cin>>m>>n; for (int i=1;i<=n;i++) { cin>>nums[i]; } sort(nums+1,nums+1+n); int l=1,r=n; int ans=0; while (l<r) { if (nums[l]+nums[r]>m) { //不能分组 r--; } else { ans++; fg[l]=true,fg[r]=true; r--; l++; } //dbg(fg,n); } for (int i=1;i<=n;i++) { if (fg[i]==false) { ans+=1; } } cout<<ans; #define one 1 return 0; }
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209591.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)