区间贪心算法

区间选点

区间贪心的套路就是对已有数据按某以特定属性排序,反逐个访问这些数据,判断出最优解

数轴上有N个闭区间[Ai, Bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。什么是闭区间

输入
第1行:一个整数N(1 <= N <=100000)
接下来N行,每行2个整数Ai,Bi(-10^7 <= Ai < Bi < 10^7)

输出
第1行:一个整数,表示满足条件的最少点数。

样例输入
5
4 6
2 3
1 4
6 8
5 7
1
2
3
4
5
6
样例输出
2
分析:将所有线段按左端点递增排序,如果有某一个线段L1被线段L2完全包围,则不再考虑L2。按左端点从小到大逐个访问线段
在这里插入图片描述

#include<cstdio>
#include<algorithm>
using namespace std;
struct mn{
    int a,b;
    bool operator < (const mn& S)const
    {  
        return b<S.b||b==S.b&&a>S.a;  
    }
}mn[100005];
int n,t,k=1;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&mn[i].a,&mn[i].b);
    sort(mn+1,mn+n+1);
    for(int j=2;j<=n;j++)
        if(mn[k].b<mn[j].a){
		t++;
		k=j;
	}
    printf("%d\n",t+1);
}

原文见[原文]

区间完全覆盖问题

问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖

样例:区间长度8,可选的覆盖线段[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]
 
分析:将所有区间按左端点递增排序,设置两个变量A,B、A表示目前区间的右端点,B表示左端点被A表示区间覆盖的区间的右端点,找到B的最大值,不断更新。

原文

最大不相交覆盖

问题描述: 给定一个长度为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 、第一步选取[2,4],发现后面只能加入[6,8],所以区间的个数为2
3、贪心证明: 因为需要尽量多的独立的线段,所以每个线段都尽可能的小,对于同一右端点,左端点越大,线段长度越小。那么为什么要对右端点进行排序呢?如果左端点进行排序,那么右端点是多少并不知道,那么每一条线段都不能对之前所有的线段进行一个总结,那么这就明显不满足贪心的最有字结构了。和之前的按左端点排序不同

猜你喜欢

转载自blog.csdn.net/Cai__ji/article/details/84838761