XCPC第十三站,贪心问题

这篇博客探讨了贪心算法在解决区间问题中的应用,包括区间选点、最大不相交区间数量、区间分组、区间覆盖、排队打水、货仓选址和耍杂技的牛等问题。通过贪心策略,博主展示了如何找到最优解并证明其正确性。
摘要由CSDN通过智能技术生成

在这里插入图片描述

一.区间选点

在这里插入图片描述
        我们采取这样的策略来选点:step(1)将区间按照右端点的大小从小到大排序;step(2)从前往后依次枚举每个区间,如果当前区间中已经包含点,直接pass,否则选当前区间的右端点。因为右端点是最容易被下一个区间包含进去的,所以我们每次选择的都是当前情况下的局部最优解,这种策略就叫作贪心。
        设最优解的点数是ans,按照算法找到的点数是cnt,下面我们证明ans == cnt。首先证明ans<=cnt。根据算法思路,这样选择以后每个区间都包含了点(否则会选右端点),因此算法得到一个可行解。又ans是所有可行解的最小值,因此ans<=cnt。再证明ans>=cnt。如果要执行选一个新的点的操作,那么后一个区间和前一个区间一定无交集。这样一来,我们就至少得到了cnt个互不相交的区间,每个这样的区间我们都选了它的右端点。要覆盖这些区间至少需要cnt个点,因此ans>=cnt。终上,ans == cnt。

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int res;
struct range
{
   
    int l,r;
    bool operator< (const range W)const
    {
   
        return r<W.r;
    }
}range[N];
int main()
{
   
    int n;
    cin>>n;
    //要从0开始读入而不能从1开始读入,因为排序的是编号从0到(n-1)的数据,如果读到n的话会导致最后一个数据没有排序。
    //从小到大枚举每个区间
    for(int i = 0;i<n;i++)
    {
   
        int a,b;
        cin>>a>>b;
        range[i] = {
   a,b};
    }
    sort(range,range+n);
    //ed表示枚举的上一个区间的右端点。初始时赋值为负无穷,这是因为第一次总是要加点的。
    int ed = -2e9;
    //要从0开始不能从1开始,理由同上
    for(int i = 0;i<n;i++)
    {
   
    //上一个区间的右端点小于当前区间的左端点,说明两个区间没有交集,那么就要选一个新的点
        if(ed<range[i].l)
        {
   
            res++;
            //更新右端点的值
            ed = range[i].r;
        }
    }
    cout<<res<<endl;
}

二.最大不相交区间数量

在这里插入图片描述

        本题代码与上一题完全相同。下面我们来说明为什么按照上题策略选出的点数即为最大不相交区间数量。设ans为最大不相交区间数量,cnt为按照算法找出的区间数量。根据上题,根据算法选出的区间没有交集,因此是一个可行解。而ans是可行解的最大值,因此ans>=cnt。再证明ans<=cnt。采用反证法。假设ans>cnt,说明我们可以找到ans个互不相交的区间,要用点把这些区间覆盖至少需要ans>cnt个点。但是根据第一题,cnt个点已经可以把所有选出的区间覆盖,矛盾。终上,ans ==cnt。

三.区间分组

在这里插入图片描述
        对于本题,我们的策略如下:step(1)将所有区间按照左端点从小到大排序;step(2)从前往后枚举所有区间,枚举当前已有的所有组,判断能否将该区间放进已有的某个组中(即判断某个是否有某个组的区间的右端点最大值小于当前区间的左端点,若<,可以放机;否则无法放进)。若可以放进某个组,就放进去并更新该组右端点的最大值;若不存在这样的组,就开一个新组把这个区间放进去。

#include<iostream>
#include<algorithm></
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值