暑假acwing算法总结28:区间贪心

  • 1、区间选点(最大不相交区间数量)(区间合并)
  • 与之前不同的是脑子里可以有最优解的模型
  • 以上三个问题对应到贪心上面都是一个问题
  • 对于贪心问题的证明,只要证明子区间改变顺序前后的答案不会更优,这样的整体区间就是最优的,以部分最优推到整体最优,看似目光短浅,但是可以证明他的正确性
  • 证明贪心解>=最优解(显而易见)
  • 问题是如何证明贪心解<=最优解
  • 像区间选点问题,先按照右端点排序要是假如有一个逆序右端点,贪心解会变少,但不是最优解,所以按右端点排序的贪心就是最优解
  • 代码
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> PP;
const int N=1e5+10;
#define f first
#define s second
PP node[N];
bool cmp(PP a,PP b)
{
    return a.s<b.s;
}
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>node[i].f>>node[i].s;
    }
    sort(node,node+n,cmp);
    int res=0,end=-0x3f3f3f3f;
    for(int i=0;i<n;i++)
    {
        if(node[i].f>end)
        {
            res++;
            end=node[i].s;
        }
    }
    cout<<res<<endl;
    return 0;
}
  • 2、区间分组
  • 按照左端点排序依次枚举,不想证明,脑子里有模型就好了
  • 有冲突就重新分组,没有冲突就把他放到堆中删掉原堆顶,加上现有的右端点
  • 代码
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10;
struct Node//结构体变量名称
{
    int l,r;
    bool operator <(const Node &w)const
    {
        return l<w.l;
    }
}node[N];//结构体数组名称
//最好不要混淆
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        cin>>l>>r;
        node[i]={l,r};
    }
    sort(node,node+n);
    priority_queue<int,vector<int>,greater<int>>heap;
    for(int i=0;i<n;i++)
    {
        Node g=node[i];
        if(heap.empty()||heap.top()>=g.l)heap.push(g.r);
        else
        {
            int t=heap.top();
            heap.pop();
            heap.push(g.r);
        }
    }
    printf("%d\n",heap.size());
    return 0;
}
  • 3、区间覆盖
  • 依旧按照左端点排序,拿到符合要求的左端点中右端点最大的就是满足条件的最优解,部分最优得到整体最优
  • 代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct Node
{
    int l,r;
    bool operator<(const Node &w)const
    {
        return l<w.l;
    }
}node[N];
int main()
{
    int start,end;
    cin>>start>>end;
    int n;cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        cin>>l>>r;
        node[i]={l,r};
    }
    sort(node,node+n);
    int res=0;
    int flag=0;
    for(int i=0;i<n;i++)
    {
        int j=i,r=-0x3f3f3f3f;
        while(j<n && node[j].l<=start)
        {
            r=max(r,node[j].r);
            j++;
        }
        if(r<start)
        {
            res=-1;
            break;
        }
        res++;
        if(r>=end)
        {
            flag=1;
            break;
        }
        start=r;
        i=j-1;
    }
    if(!flag)res=-1;
    cout<<res<<endl;
    return 0;
}
  • 2021-7-30写于商丘

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值