算法分析
-
将每个区间按照右端点从小到大进行排序
-
从前往后枚举区间,end值初始化为无穷小
-
如果本次区间不能覆盖掉上次区间的右端点,
ed < range[i].l
说明需要选择一个新的点,
res ++ ; ed = range[i].r;
- 如果本次区间可以覆盖掉上次区间的右端点,则进行下一轮循环
-
时间复杂度 $O(nlogn)$
证明
-
证明
ans<=cnt
:cnt
是一种可行方案,ans
是可行方案的最优解,也就是最小值。 -
证明
ans>=cnt
:cnt
可行方案是一个区间集合,区间从小到大排序,两两之间不相交。所以覆盖每一个区间至少需要cnt个点。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const
{
return r < W.r;
}
}range[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d%d", &range[i].l, &range[i].r);
sort(range, range + n);
int res = 0, ed = -2e9;
for (int i = 0; i < n; i ++ )
if (ed < range[i].l)
{
res ++ ;
ed = range[i].r;
}
printf("%d\n", res);
return 0;
}
大家都证明得很牵强,让我也来证明一下,如果有问题,欢迎指出。疑惑点在ans>=cnt,我们可以假设有ans小于cnt,且咋们用算法求出来的区间用数组t表示。那么这个ans肯定要包含咋们算法求出来的区间。那这个ans可不可能有个区间跨越了咋们求出来的区间t的两个区间呢。显然不可能,这是算法证明的关键。因为如果有这么一个区间的话,咋们贪心算法肯定能找出来,那么t区间就不是咋们算法求解出来的区间了。所以ans连我们数组t都覆盖不了,他还想覆盖全部,简直想屁吃。
反证法确实更好一些
我对你的证明理解是这样的:
假设有ans < cnt,我们的算法求出来的区间(注意这些区间都是两两不相交的)用数组t(因为选的点都是某个区间的右端点,且点都是不同的,因此可以用这个点当做某个区间)表示。那么这个ans中的点肯定要包含我们算法求出来的区间。那这ans个点中是否有一个点,使得在 t 有两个区间都包含这个点呢?显然不可能。我们求出来的区间数量 t 还不是全部的区间数。因此ans>= cnt。
不知道对不对,呵呵
为啥我觉得跟答主写的没啥区别,只是你用了反证而已
大佬,我对这里的证明有点疑问,求解。
(1) 证明ans<=cnt 时,你这里的ans指的是可行方案中最少需要的点数;
(2) 证明ans>=cnt 时,你这里的ans指的是可行方案中需要用到的点数。
ans中一个是最少,一个是一般,好像不是指向同一个东西了
这里就证明的很牵强
最优解$ans$:所有合法方案中的最小值,贪心解$cnt$
(1)上述选法必然会使每个区间里至少包含一个点,是一种合法方案,所以$ans<=cnt$
(2)通过贪心方案我们知道序列中包含了$cnt$个相互之间没有交集的区间,所以对于一个合法方案,必然至少包含$cnt$个点,所以$cnt<=ans$
一点拙见
##### 证明:
ans <= cnt :
ans 作为最优解
==反证法:因为ans是由cnt产生的,如果ans>cnt,则ans不是最优解==
ans >= cnt :
ans要覆盖所有的区间
==反证法:因为ans是由cnt产生的,如果ans<cnt,则无法通过cnt产生ans==
这里的sort()实现右端点排序是什么原理,sort()怎么知道是以r为标准排序
因为前面只对结构体的右端点的属性值进行了重载,也就是说只有右端点能进行比较,自然是按照r为标准排序的
而且这里是用结构体类型来存储左右端点,事实上如果直接用pair和vector来存和比较的话是不需要重载运算符的
这里的cnt貌似不是指的一个东西吧
对,感觉cnt的概念变了
对于$ans \geq cnt$的证明:由贪心策略可知,贪心方法将会选择尽量少的点覆盖所有的区间,且每个点对应的区间的集合不相交;使用反证法,不妨假设$ans<cnt$成立,由于$ans$是最优解,那么$ans$个点也覆盖所有的区间,即存在更少的点$ans$可以覆盖所有的区间。这与贪心策略不符,因为一旦有更少的点可以覆盖所有的区间,那么它一定是贪心解$cnt$,否则更少的点不能覆盖所有的区间,与假设矛盾。因此$ans \geq cnt$成立
怎么哪都有你!
已经失联好几个月哩
想知道为什么
for(int i = 1 ; i <= n ; i++)
这样读入 会Wa掉呢后面判断那里,你并没有从第一个区间开始遍历
你存的时候没有用零号下表,但是你排序时是从零号下标开始排的,最后一个点没有排序
看到了看到了hh
眼高手低和我一样
时间复杂度 为什么是O(nlogn)呢?
sort排序的时间复杂度为O(nlogn)
懂了,忽略了这个hh
ok
这个图清楚明白
orz
nb
https://blog.csdn.net/qq_52416556/article/details/136434922?spm=1001.2014.3001.5502 最新图解
#include [HTML_REMOVED]
using namespace std;
vector[HTML_REMOVED]> segs;
vector[HTML_REMOVED]> merges;
int n;
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
int a, b;
cin >> a >> b;
segs.push_back({a, b});
}
}
用STL
建议用cmp