ural 1303 Minimal Coverage【贪心】
链接:
Description
Given set of line segments [Li, Ri] with integer coordinates of their end points. Your task is to find the minimal subset of the given set which covers segment [0, M] completely (M is a positive integer).
Input
First line of the input contains an integer M (1 ≤ M ≤ 5000). Subsequent lines of input contain pairs of integers Li and Ri (abs(Li), abs(Ri) ≤ 50000). Each pair is placed on separate
line. Numbers in the pair are separated with space(s). List of pairs is ended with pair of zeroes. The list contains no more than 100000 pairs, including the pair of zeroes.
Output
Your program should print in the first line of output the power of minimal subset of segments which covers segment [0, M]. The list of segments of covering subset must follow. Format of the list must be the same as described
in input with exception that ending pair of zeroes should not be printed. Segments should be printed in increasing order of their left end point coordinate.
If there is no covering subset then print "No solution" to output.
Sample Input
input | output |
---|---|
1 -1 0 -5 -3 2 5 0 0 |
No solution |
1 -1 0 0 1 0 0 |
1 0 1 |
题意:
看的这里的翻译才懂的了= = 题目翻译
读入一个整数m(1<=m<=5000)。 接下来若干行,表示若干条线段。 从l[i]到r[i](最多100000条线段)。 到一行0 0为止。 求最少要用多少条线段可以覆盖区间[0,m]。 输出第一行一个数字,表示最少线段数。 接下来若干行表示选择的线段。按照顺序!!!注意:这里的按照顺序不是指线段输入的顺序而是每条线段的左右点的顺序 若无解则输出'No solution'。
算法: 贪心
思路:
后来KB大神有说了一遍,然后和Orc讨论了下楼上的code才出来。
先按照输入的线段从左到右排序(即起点升序),排序时把被覆盖的线排再后面,程序中再忽略被覆盖的线
【不存在i,j使(l[i]<=l[j])&&(r[i]>=r[j]),即不存在某条线段被覆盖的情况】
为什么要删除被覆盖的线?因为如果选择了被覆盖的线,那么如果换成选择覆盖它的线结果不会更坏。
然后贪心
贪心的过程中先找出满足条件的覆盖 0 的线段,再以选择的这条线段的右端点的值为覆盖点,继续按照上面的步骤覆盖这个覆盖点,直到覆盖了 m 为止。
如何贪这样的满足的线段?
思路:找出所有的覆盖了这个点的线段,然后选择右端点最大的就可以了。
如果一个个存或者比较的话很费时间和内存,那么开始的排序和删除被覆盖了的线就起到了作用,程序中稍微调整就可以满足情况。当所有的被覆盖了的线都删除了的时候,依次遍历所有的线,如果这条线覆盖了当前需要覆盖的点,而它的下一条线没有覆盖当前要覆盖的点,那么这就是要选择的线。也就是前面分析的覆盖了当前点的右端点最大的,因为重复的都删除了。
删除覆盖的:
最终可能状态:
code:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int maxn = 100000+10; struct Line{ int left,right; }line[maxn], ans[maxn]; bool cmp(Line L1, Line L2) //从左到右排序,覆盖掉被其他线包含的线 { if(L1.left != L2.left) return L1.left < L2.left; else return L1.right >= L2.right; } int main() { int m; while(scanf("%d", &m) != EOF) { int left,right; int n = 0; for(;;) { scanf("%d%d", &left,&right); if(left == 0 && right == 0) break; line[++n].left = left; line[n].right = right; } sort(line+1, line+n+1, cmp); int num = 1; for(int i = 2; i <= n; i++) //覆盖过程 { if(line[i].left > line[num].left && line[i].right > line[num].right) line[++num] = line[i]; } n = num; line[n+1].left = line[n+1].right = m+1; //边界处理 int cover = 0; //当前要求覆盖的点 int total = 0; //当前选中了的线 for(int i = 1; i <= n; i++) { if(line[i+1].left > cover && line[i].left <= cover) { ans[++total] = line[i]; cover = line[i].right; if(cover >= m) { printf("%d\n", total); for(int j = 1; j <= total; j++) { printf("%d %d\n", ans[j].left, ans[j].right); } return 0; //退出程序 } } } printf("No solution\n"); } return 0; }