• 基于贪心算法的几类区间覆盖问题


    基于贪心算法的几类区间覆盖问题:

    (1)区间完全覆盖问题
    问题描述:
    给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),
    求最少使用多少条线段可以将整个区间完全覆盖
    样例:
    区间长度8,可选的覆盖线段[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]
    解题过程:
    1、将每一个区间按照左端点递增顺序排列,拍完序后为[1,4],[2,4],[2,6],[3,5],
    [3,6],[3,7],[6,8]
    2、设置一个变量表示已经覆盖到的区域。再剩下的线段中找出所有左端点小于等于当前
    已经覆盖到的区域的右端点的线段中,右端点最大的线段在加入,直到已经覆盖全部的区域
    3、过程:
    假设第一步加入[1,4],那么下一步能够选择的有[2,6],[3,5],[3,6],[3,7],
    由于7最大,所以下一步选择[3,7],最后一步只能选择[6,8],这个时候刚好
    达到了8退出,所选区间为3
    4、贪心证明:
    需要最少的线段进行覆盖,那么选取的线段必然要尽量长,而已经覆盖到的区域之前
    的地方已经无所谓了,(可以理解成所有的可以覆盖的左端点都是已经覆盖到的地方),
    那么真正能够使得线段更成的是右端点,左端点没有太大的意义,所以选择右端点来覆盖

    (2)最大不相交覆盖(我总感觉这个算法不对,这不应该和会议安排问题一样吗? 直接按照终点排序再依次选择???)
    问题描述:
    给定一个长度为m的区间,再给出n条线段的起点和终点(开区间和闭区间处理的方法是
    不同,这里以开区间为例),问题是从中选取尽量多的线段,使得每个线段都是独立的,
    就是不和其它有任何线段有相交的地方
    样例:
    区间长度8,可选的覆盖线段[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]
    解题过程:
    对线段的右端点进行升序排序,每加入一个线段,然后选择后面若干个
    (也有可能是一个)右端点相同的线段,选择左端点最大的那一条,如果加入以后不会
    跟之前的线段产生公共部分,那么就加入,否则就继续判断后面的线段
    1、排序:将每一个区间按右端点进行递增顺序排列,拍完序后为[1,4],[2,4],[3,5],[2,6],
    [3,6],[3,7],[6,8]
    2、第一步选取[2,4],发现后面只能加入[6,8],所以区间的个数为2
    3、贪心证明:因为需要尽量多的独立的线段,所以每个线段都尽可能的小,
    对于同一右端点,左端点越大,线段长度越小。那么为什么要对右端点进行排序呢?
    如果左端点进行排序,那么右端点是多少并不知道,那么每一条线段都不能对之前所有
    的线段进行一个总结,那么这就明显不满足贪心的最有字结构了。

    (3)区间选点问题
    问题描述:
    给定一个长度为m的区间,再给出n条线段和这n条线段需要满足的要求
    (要求是这n条线段上至少有的被选择的点的个数),问题是整个区间内最少
    选择几个点,使其满足每一条线段的要求.
    样例:略
    解题过程:
    将每个线段按照终点坐标进行递增排序,相同终点的前点坐标从大到小排列,
    一个个将其满足(每次选择的点为该条线段的右端点)
    贪心证明:
    要想使得剩下的线段上选择的点最少,那么就应该尽量使得已经选择了的点尽量能
    在后面的线段中发挥作用,而我们是从左往右选择线段的,那么要使得选取的点能
    满足后面线段的要求,那么必须是从线段的右端点开始选点,那么问题(2)一样涉及
    到一个问题,如果是按照线段的左端点对线段进行排序的话,不知道右端点的话,
    每一条线段都不能对之前已经操作过的所有线段进行一个总结,那么这就同样不满足
    贪心算法的最优子结构性质了。
    可以解决的实际问题:数轴上面有n个闭区间[a,b],取尽量少的点,使得每个区间内都
    至少有一个点(不同区间内含的点可以是同一个)

    应用例题:(貌似不是很简单。。。)
      有一列整数,他的每一个数各不相同,我们不知道有多少个,但我们知道在
    某些区间中至少有多少个整数,用区间(L,R,C)来描述,表示整数序列
    中至少有C个整数来自子区间[L, R],若干个这样的区间,问这个整数序列的长
    度最少能为多少。

    区间选点算法实现:

     1 #include <iostream>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 struct line
     7 {
     8     int left;
     9     int right;
    10 }a[100];
    11 
    12 bool cmp(line p, line q)
    13 {
    14     if(p.right != q.right)
    15         return p.right < q.right;
    16     return p.left > q.left;
    17 }
    18 
    19 int main()
    20 {
    21     int n;
    22     while(cin >> n)
    23     {
    24         for(int i = 0; i < n; ++i)
    25             cin >> a[i].left >> a[i].right;
    26         sort(a, a + n, cmp);
    27         int cnt = 0;
    28         int end = -1;
    29         for(int i = 0; i < n; ++i)
    30         {
    31             if(end >= a[i].left && end <= a[i].right)
    32                 continue;
    33             else
    34             {
    35                 ++cnt;
    36                 end = a[i].right;
    37             }
    38         }
    39         cout << cnt << endl;
    40     }
    41     return 0;
    42 }
  • 相关阅读:
    Linux下安装maven
    非连续性及反脆弱
    高手是怎么练成的
    思维型大脑
    编写文档五轮模式
    Nginx初识
    ida快捷键
    ida+gdb调试任意平台
    gcc常用命令使用
    ida调试ios应用
  • 原文地址:https://www.cnblogs.com/dongsheng/p/3030444.html
Copyright © 2020-2023  润新知