第六章 贪心 完结

Posted 辉小歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第六章 贪心 完结相关的知识,希望对你有一定的参考价值。

贪心类题型没有固定的模板只有多做题,总结经验。

905. 区间选点

在这里插入图片描述
https://www.acwing.com/problem/content/description/907/

本题和区间合并那种题几乎一样的思路,不过还是有差别的。
首先:按左端点从小到达排,这是没有悬念的必须做的。
这时候分析,会有如下几种情况:
情况一:
在这里插入图片描述
这种包含的情况,我们要选小的,因为我们要的是公共部分。
情况二:
在这里插入图片描述
这种相交的情况选,相交的。
情况三:
在这里插入图片描述
不相交的情况选b,个数加1。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct student 
{
    int x,y;
}stu[N];
bool cmp(student a,student b)
{
    return a.x<b.x;
}
int main(void)
{
    int n; cin>>n;
    
    for(int i=0;i<n;i++) cin>>stu[i].x>>stu[i].y;
    
    sort(stu,stu+n,cmp);
    
    int ans=1;
    int startx=stu[0].x,endx=stu[0].y;
    for(int i=1;i<n;i++)
    {
        if(stu[i].x<=endx&&stu[i].y<=endx) startx=stu[i].x,endx=stu[i].y;
        else if(stu[i].x<=endx&&stu[i].y>endx) startx=stu[i].x;
        else ans++,startx=stu[i].x,endx=stu[i].y;
    }
    cout<<ans<<endl;
    return 0;
}

方法二 从小到大排序右端点:
在这里插入图片描述
因为我们选右端点,才可能尽量大的覆盖掉后面的区间

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=1e5+10;
struct node
{
    int x,y;
}Node[N];
bool cmp(node a,node b)
{
    return a.y<b.y;
}
int main(void)
{
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
    sort(Node,Node+n,cmp);
    int ans=0;
    int flag=-1e9;
    for(int i=0;i<n;i++)
    {
        if(flag<Node[i].x) ans++,flag=Node[i].y;
    }
    cout<<ans<<endl;
    return 0;
}

908. 最大不相交区间数量

在这里插入图片描述
https://www.acwing.com/problem/content/910/

老规矩:左端点从小到大排序
第一种情况:
在这里插入图片描述
这种得选a,这样右边的区间的选择范围才会更大。
第二种情况:
在这里插入图片描述
此时不用变,还是a这样才会有更大的空间。
第三种情况:
在这里插入图片描述
选b,数量加1

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct student
{
    int x,y;
}stu[N];
bool cmp(student a,student b)
{
    return a.x<b.x;
}
int main(void)
{
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>stu[i].x>>stu[i].y;
    sort(stu,stu+n,cmp);
    
    int ans=1;
    int startx=stu[0].x,endx=stu[0].y;
    
    for(int i=1;i<n;i++)
    {
        if(stu[i].y<endx) startx=stu[i].x,endx=stu[i].y;
        else if(stu[i].x>endx) ans++,startx=stu[i].x,endx=stu[i].y;
    }
    
    cout<<ans<<endl;
    return 0;
}

方法二:从小到大排序右端点

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node
{
    int x,y;
}Node[N];
bool cmp(node a,node b)
{
    return a.y<b.y;
}
int main(void)
{
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
    sort(Node,Node+n,cmp);
    int ans=0;
    int flag=-1e9;
    for(int i=0;i<n;i++)
    {
        if(Node[i].x>flag) ans++,flag=Node[i].y;
    }
    cout<<ans<<endl;
    return 0;
}

906. 区间分组 【有意思】

在这里插入图片描述
https://www.acwing.com/problem/content/description/908/

在这里插入图片描述

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node
{
    int x,y;
}Node[N];
bool cmp(node a,node b)
{
    return a.x<b.x;
}
int main(void)
{
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
    sort(Node,Node+n,cmp);
    priority_queue<int, vector<int>, greater<int> >heap;
    for(int i=0;i<n;i++)
    {
        if(heap.empty()||heap.top()>=Node[i].x)//组为空,或者任何一个组内都放不下
        {
            heap.push(Node[i].y);
        }
        else if(heap.top()<Node[i].x)//可以放进组内
        {
            heap.pop();//将原来的区间的最右值更新
            heap.push(Node[i].y);
        }
    }
    cout<<heap.size()<<endl;
    return 0;
}

907. 区间覆盖【有意思】

在这里插入图片描述
https://www.acwing.com/problem/content/description/909/
在这里插入图片描述
对于可以覆盖之前的,我们要选它们中最长的。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node
{
    int x,y;
}Node[N];
bool cmp(node a,node b)
{
    return a.x<b.x;
}
int main(void)
{
    int st,ed; cin>>st>>ed;
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>Node[i].x>>Node[i].y;
    sort(Node,Node+n,cmp);

    int res=0;
    bool flag=false;
    for(int i=0;i<n;i++)
    {
        int j=i,r=-1e9;
        while(j<n&&Node[j].x<=st)//找到最大的右端点
        {
            r=max(r,Node[j].y);
            j++;
        }

        if(r<st)//说明r没有更新,说明这两段没有公共部分,故不能覆盖
        {
            res=-1;
            break;
        }

        res++;
        if(r>=ed)//覆盖完了
        {
            flag=true;
            break;
        }
        st=r;//更新
        i=j-1;
    }
    if(!flag) cout<<-1<<endl;
    else cout<<res<<endl;
    return 0;
}

148. 合并果子

在这里插入图片描述
https://www.acwing.com/problem/content/description/150/

方法:每次选最小的两个合并。

小根堆做法

#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
int main(void)
{
    priority_queue<int, vector<int>, greater<int> >heap;
    int n; cin>>n;
    while(n--)
    {
        int x; cin>>x;
        heap.push(x);
    }
    long long int res=0;
    while(heap.size()>1)
    {
        int a=heap.top(); heap.pop();
        int b=heap.top(); heap.pop();
        res+=a+b;
        heap.push(a+b);
    }
    cout<<res<<endl;
    return 0;
}

大根堆做法

#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
int main(void)
{
    int n; cin>>n;
    priority_queue<int> heap;
    while(n--)
    {
        int x; cin>>x;
        heap.push(-x);
    }
    long long int res=0;
    while(heap.size()>1)
    {
        int a=heap.top(); heap.pop();
        int b=heap.top(); heap.pop();
        res+=(-a-b);
        heap.push(-(-a-b));
    }
    cout<<res<<endl;
    return 0;
}

913. 排队打水

在这里插入图片描述
https://www.acwing.com/problem/content/description/915/

思路: 由于若把时间长的放在后面接水,那么就较少人等,所以排序+贪心即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
long long int a[N],s[N];
int main(void)
{
    int n; cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    long long int sum=0;
    for(int i=1;i<=n-1;i++) s[i]=s[i-1]+a[i],sum+=s[i];
    //1代表的就是第二个人的等待时间,第一个人的等待时间为零
    cout<<sum<<endl;
    return 0;
}

104. 货仓选址

在这里插入图片描述

https://www.acwing.com/problem/content/description/106/
选中间的位置最优

详细的证明

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N],sum;
int main(void)
{
    int n; cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    int area=a[n/2];
    for(int i=0;i<n;i++) sum+=abs(area-a[i]);
    cout<<sum<<endl;
    return 0;
}

125. 耍杂技的牛

在这里插入图片描述
https://www.acwing.com/problem/content/description/127/

按其和从小到大排序

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct student
{
    int w,s;
}以上是关于第六章  贪心 完结的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud基础组件完结--第七章

第六章:异常机制

Python核心编程(第二版)第六章部分习题代码

《集体智慧编程》代码勘误:第六章

《HALCON数字图像处理》第六章笔记

第六章 包含多个段的程序