基础算法 - 贪心入门

本文介绍了贪心算法的基本思想,通过两个例题——Luogu P2095 营养膳食和Luogu P2695 骑士的工作,详细讲解了如何应用贪心算法解决问题。在营养膳食问题中,关键在于按脂肪含量排序食物;而在骑士工作问题中,关键在于对骑士能力和龙头大小进行排序。贪心算法在日常刷题和竞赛中都有广泛的应用。
摘要由CSDN通过智能技术生成

前言

贪心贪心,顾名思义,就是说你要很贪
(当然你可能会被抓)
不同于 动态规划 的目光长远,贪心 往往“鼠目寸光”,只注重眼前的利益
而这也是贪心的定义:
在当前情况下寻找 局部 最优解
所以当你确定一道题目是贪心时,不要想太多,每次取最优即可
纵使后面可能会有更好的情况,那也不关咱们的事
(谁让咱们贪呢)
当然有一些贪心题看起来很像dp,千万别搞混(比如例题第一题)

例题

Luogu P2095 营养膳食

注意:这题不是dp,这题不是dp,这题不是dp!
(我还信誓旦旦地说这是背包来着)
第一遍看我就只想到了 dp ,写了 10min 之后发现 dp 完全无法实现
所以这题是贪心无疑
那么我们怎么贪呢?

大家应该还记得贪心的定义,所以我们每次只要吃脂肪尽可能多的就可以了

做法:
1. 读入每种食物最多吃多少份
2. 读入食物的脂肪和种类
3. 按脂肪排序(核心部分 非常重要)
4. 排序部分我们从大到小排,所以从第一份开始判断(i from 1 to m)
5. 先判断还能不能吃这一种
6. 再判断有没有越界( nown
7. 符合条件直接加上即可
写完之后我们会发现,得出的就是最优解,因为脂肪最多的那些都被我们吃掉了
代码仅供参考:

#include<cstdio>
#include<algorithm>//使用sort函数
using namespace std;
int n,m,k,Max_Eat[105],ans;
struct node//创建结构体存信息
{
    int Fat,Type;//脂肪和种类
}a[205];
bool cmp(node x,node y)//sort的判断用函数
{
    return x.Fat>y.Fat;//从大到小排
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=k;i++) scanf("%d",&Max_Eat[i]);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].Fat,&a[i].Type);//读入数据
    sort(a+1,a+n+1,cmp);//核心的排序部分
    int tot=1;//tot代表现在吃到了第几份
    for(int i=1;i<=m;i++)//最多吃m份
    {
        if(Max_Eat[a[tot].Type]>0 && tot<=n)//如果符合条件
        {
            ans+=a[tot].Fat;//直接加上
            Max_Eat[a[tot].Type]--;//这一步也很重要,当前种类能吃的份数-1
            tot++;//到下一份
        }
        else tot++;//如果不能吃也到下一份
    }
    printf("%d",ans);//输出即可
    return 0;
}

再来一道:

Luogu P2695 骑士的工作

这道题目是一题比较明显的贪心,我们需要让每个骑士砍掉他所能砍的最小的头
那么有人就要问了:这怎么实现呢?
排序呗!
(实际上大多贪心的题目都要用到排序,sort是一个必须要学的东西)

做法:
1. 读入每个骑士能砍的头的大小
2. 读入龙头的大小
3. 分别排序(核心代码 从小到大排)
4. 对每个骑士进行判断,让他砍掉他所能砍的最小的头
5. 如果能砍 ans+k[i] ,同时 sum+1
6. 如果 sum<n 输出 you died! , 否则输出 ans
当然我们可以进行一些小小的优化
注意:每个骑士只能砍一个龙头
代码仅供参考:

#include<cstdio>
#include<algorithm>//sort大法好
using namespace std;
int n,m,d[20005],k[20005],ans,sum;
bool used[20005];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&d[i]);
    for(int i=1;i<=m;i++) scanf("%d",&k[i]);//读入数据
    if(n>m)//小优化,如果骑士比恶龙少直接就可以放弃治疗【划掉】退出程序了
    {
        printf("you died!");
        return 0;
    }
    sort(d+1,d+n+1);
    sort(k+1,k+m+1);//排序
    for(int i=1;i<=n;i++)
    {
        bool Can_Kill=false;//用来存储能不能砍掉龙头
        for(int j=1;j<=m;j++)
        {
            if(used[j]) continue;//used数组存储龙头是否已经被砍
            if(k[j]>=d[i])//由于排序过,所以第一个能砍的必然是能砍的最小的头
            {
                ans+=k[j];//费用加上
                Can_Kill=true;//能杀
                sum++;//又杀了一头
                used[j]=true;//这头龙已死
                break;//退出循环
            }
        }
        if(!Can_Kill)//不能杀的话直接 欢声笑语中打出GG
        {
            printf("you died!");
            return 0;
        }
    }
    if(sum==n) printf("%d",ans);
    else printf("you died!");//判断输出即可
    return 0;
}

小结

贪心不论是在 日常刷题 还是在 竞赛 中,使用都非常广泛
相信参加过竞赛(甚至是模拟赛)的同学都知道贪心是一种十分优秀的骗分方法
所以贪心还是有必要多学多练的

原创 By Venus
写的不好大佬轻喷

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值