基础算法

来源:互联网 发布:压缩包密码破解 知乎 编辑:程序博客网 时间:2024/06/03 21:28

前言

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

原创粉丝点击