区间贪心
1.区间不相交问题
给出 N 个开区间(x, y),从中选择尽可能多的开区间,使得这些开区间两两没有交集。例如对于开区间(1, 3)、(2, 4)、(3, 5)、(6, 7)来说,可以选出最多三个区间(1, 3)、(3, 5)、(6, 7),它们之间没有交集。
思路分析
- 最简单的情况(如图a),如果开区间 I1 被开区间 I2 包含,则选择 I1 是最好的选择,如果选择了 I1 ,就会有更大的区间如容纳其他开区间。
- 将所有的开区间按左端点x从大到小排序,如果去掉区间包含的情况,那么一定会有 y1 > y2 > ... > yn 成立,如图b。可以看出I1的右边一段一定不会和其他区间重叠的,如果把它去掉,那么I1的左边的剩余部分就会被I2包含,因此应该选择 I1 。最终总是先选择左端点最大的区间。
代码
#include <cstdio>
#include <algorithm>
#include <climits>
using namespace std;
const int N = 110;
struct Interval
{
int x, y;
bool operator< (const Interval &a) const
{
if (a.x != x) return x > a.x;
else return y < a.y;
}
}I[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++)
scanf("%d%d", &I[i].x, &I[i].y);
sort(I, I + n);
int ans = 1, lastX = INT_MAX;
for (int i = 0; i < n; i ++)
if (I[i].y <= lastX)
{
lastX = I[i].x;
ans ++;
}
printf("%d\n", ans);
return 0;
}
2.区间选点问题
给定 N 个闭区间[x, y],求最少需要确定多少个点,才能使每个闭区间中都至少存在一个点。
思路分析
如果闭区间I1被闭区间I2包含,那么在I1中的点一定包含在I2中。将所有区间按左端点由大到小排序,接下来只取左端点,这样这个点就能覆盖尽可能多的区间。
代码
只需将上文代码中的I[i].y <= lastX
改为I[i].y < lastX
即可。
原因:在区间不相交问题中,区间使开区间,当端点重合时,两个区间并没有相交。在本问题中,区间是闭区间,端点重合时,当前区间一定包含上一个区间的左端点,因此可以忽略当前区间。
#include <cstdio>
#include <algorithm>
#include <climits>
using namespace std;
const int N = 110;
struct Interval
{
int x, y;
bool operator< (const Interval &a) const
{
if (a.x != x) return x > a.x;
else return y < a.y;
}
}I[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++)
scanf("%d%d", &I[i].x, &I[i].y);
sort(I, I + n);
int ans = 1, lastX = INT_MAX;
for (int i = 0; i < n; i ++)
if (I[i].y < lastX)
{
lastX = I[i].x;
ans ++;
}
printf("%d\n", ans);
return 0;
}
参考资料《算法笔记》.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。