区间选点+区间覆盖

区间选点+区间覆盖

区间选点问题(选择最少的点,使得每个区间都至少有k个点)

将这些区间[l,r]先按照r从小到大排序,再按照l从大到小排序。选点尽量选择靠近右边界的点。然后按照这个排序后的区间进行遍历,用一个变量来存放遍历过程中上个区间的右边界,然后碰到一个新的区间的时候需要分两种情况讨论:1、这个区间和上个区间有相交的部分,那么就需要判断一下上次选择的点有多少在这个区间内,这些点满足要求吗?不满足的话还需要在这个区间内选点2、这个区间和上个区间没有交集,那么这个区间就需要选点。

上述策略可以保证右边界相同的区间,先选择区间短的那个。因为短区间的点被选择了,那么相同右边界的更大的区间肯定包含这个比较小的区间选择的所有点,这样这个大点的区间被满足的可能性就比较大了。并且这里选点的策略是取尽量靠近右边界的点,这样选取被满足区间个数会是最大的。

伪代码
    interval[maxn][2];
    sort(interval, interval + maxn, cmp);//cmp按照r小l大优先级高来排列

    pre = interval[1][0] - 1;   //制造出不相交的右边界
    for in range(1, maxn):
        if interval[i][0] > pre://不相交
            //靠近右边界选点
        else:
            //先查找这个区间已经被选中了多少点,然后根据是否满足要求再进行选点
        pre = interval[1][1]; //更新右边界
    else:;

题目:uva10148Advertisement(区间选点)

区间覆盖问题(选择最少的区间使得覆盖[m,n])

假设覆盖的区间是[m, n].先预先处理掉和[m,n]不沾边的区间。把起点小的区间放前面,如果起点相同的区间就把长的区间放前面。做两个特判,判断起点最先的区间是否涵盖m,和最后的覆盖是否有覆盖到n。接着就是中间的判断了,中间的判断看代码吧。

伪代码
    interval[maxn][2];
    vis[maxn];//记录哪条边被选择
    //删除和[m, n]不沾边的区间,并且按照l小r大优先级高排序

    function Cover_Interval:    
        if interval[0][0] < m   //是否涵盖m
            return false;
        pre = m;//前一个选择区间的右边界,也是下个要选择区间的有效的起始边界
        t = -1;//记录前一个区间的下标,因为可能这个区间并不是最好的区间
        cover = m - 1;//目前已经覆盖了的位置

        for in range(1, maxn):
            if interval[i][0] <= pre: //满足至少覆盖到上个区间右边界pre,使得整个覆盖的区间不会断开
                if interval[i][1] > cover: //选取最长的满足上面的要求的区间
                    vis[i] = 1;
                    cover = interval[i][1]; //更新覆盖位置
                    if t != -1:             //上次选中的取消
                        vis[t] = 0;
            else:                     //不满足要求说明需要选择下个新的区间,更新pre
                pre = cover;
                if interval[i][0] > pre: //如果当前这个区间的左边界比覆盖位置更大,那么说明中间有一段是覆盖不到的
                    return false;
                t = -1;                  //新的区间清空上次选中
                i--;
            if cover >= n:
                break;
        else:;

        if cover < n
            return false;
        //输出被选择的区间according to vis[maxn]
        return true;
    function end;

题目:uva10020 - Minimal coverage(区间覆盖)uva10382 - Watering Grass(区间覆盖变形)

### 关于区间选点问题的C++贪心算法实现 #### 问题描述 区间选点问题是经典的贪心算法应用场景之一。其目标是在数轴上选择尽可能少的,使得这些可以覆盖所有给定的区间。 #### 算法核心思想 贪心算法的核心在于每次做出局部最优的选择,期望最终达到全局最优的结果。对于区间选点问题,可以通过优先处理右端较小的区间来减少所需选取的的数量[^1]。 以下是基于上述原理的一个完整的C++实现: ```cpp #include <iostream> #include <algorithm> using namespace std; const int N = 100010; struct Range { int l, r; bool operator<(const Range& W) const { return r < W.r; // 按照区间的右端升序排列 } } range[N]; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { cin >> range[i].l >> range[i].r; } // 对区间按照右端进行排序 sort(range, range + n); int res = 0; // 记录所选点的数量 int ed = -2e9; // 当前已覆盖的最大位置 for (int i = 0; i < n; i++) { if (range[i].l > ed) { // 如果当前区间的左端大于已覆盖的最大位置 res++; // 增加一个新 ed = range[i].r; // 更新最大覆盖范围到该区间的右端 } } cout << res << endl; // 输出最少需要的数 return 0; } ``` #### 代码解析 1. **结构体定义** 定义了一个`Range`结构体用于存储每个区间的左右边界,并重载了小于运算符`<`以便按右端从小到大排序[^2]。 2. **输入读取与排序** 输入所有区间并将其按右端升序排列,这样可以从最小的右端开始逐步扩展覆盖区域[^4]。 3. **遍历与判断** 使用变量`ed`记录当前已经通过选定的所能覆盖的最远位置。如果某个区间的左端超过了这个位置,则说明需要新增一个覆盖区间[^5]。 4. **结果输出** 最终输出所需的最少数作为答案。 #### 正确性证明 为了验证这种策略的有效性,假设存在一种其他方式可以在某一步获得更优解(即选择了不同的),但由于我们总是挑选最早结束的区间去更新下一个起的位置,因此不可能找到比这种方法更好的解决方案[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值