题目:uva10020 - Minimal coverage(区间覆盖)
题目大意:给出一些线段,然后问怎样取能使得最少的线段覆盖区间[0, M].
解题思路:先预处理掉那些和区间【0,M】不沾边的线段。
将线段按照起点小的排序。
接着遍历这些线段。首先先判断起点最小的点是否<=0,如果不满足这个说明它不能覆盖区间。
然后每次都小于等于当前覆盖的起点的最长线段,之后要将起点更新成这个最长线段的终点。然后接着判断下一条线段。如果更新了起点发现依然找不到满足条件的线段,说明不能覆盖。
最后还要看一下是否能够覆盖到M。
代码:
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; const int N = 100005; int m, n; int visit[N]; struct segments { int l, r; }s[N]; int cmp (const segments& a, const segments &b) { return a.l < b.l; } int Max (const int a, const int b) {return a > b ? a: b;} int solve () { memset (visit, 0, sizeof (visit)); if (s[0].l > 0) //判断能否覆盖区间起点 return 0; int st = 0; int ll = -1; int t = -1; for (int i = 0; i < n; i++) { if (s[i].l <= st) { //找符合条件的最长的线段 if (ll < s[i].r) { visit[i] = 1; if (t >= 0) visit[t] = 0; t = i; ll = Max (ll, s[i].r); } } else { if (st == ll) //更新后发现依然没有 return 0; st = ll; //更新起点 i--; t = -1; //更新起点后这个记录之前记录的线段就是确定需要,和更新后的没有关联了 } if (ll >= m) //能否覆盖终点 break; } if (ll < m) //能否覆盖终点 return 0; int count = 0; for (int i = 0; i < n; i++) if (visit[i]) count++; return count; } int main () { int t; int l, r; scanf ("%d", &t); while (t--) { scanf ("%d", &m); n = 0; while (scanf ("%d%d", &l, &r), l || r) { if (r <= 0 || l >= m) continue; s[n].l = l; s[n].r = r; n++; } sort (s, s + n, cmp); int count = solve(); printf ("%d\n", count); if (count) { for (int i = 0; i < n; i++) if (visit[i]) printf ("%d %d\n", s[i].l, s[i].r); } if (t) printf ("\n"); } return 0; }