UVa 10020 - Minimal coverage
题目大意:以[L, R]的形式给出线段的左右端点,给出一些线段,判断是否能完全覆盖区间[0, m],如果能,算出所需线段的最小个数并输出线段。
区间覆盖问题,用贪心策略。“ 突破口是区间包含和排序扫描,不过要先进行一次预处理,每个区间在[s, t](对应本题的[0, m])外的部分都应该先被切掉。在预处理后,在相互包含的情况下,小区间显然不应该被考虑。把各区间按照左边界从大到小排序。如果区间1的起点不是s, 无解,否则选择起点在s的最长区间。选择区间[ai, bi]后,新的起点应该设置为bi,并且忽略所有区间在bi之前的部分,就像预处理一样。” ——摘自《算法竞赛入门经典》
虽然说的意思明白,可是写代码的时候还是没什么头绪,只好搜代码了,有点思路后再比葫芦画瓢,还差得远啊...
1 #include <cstdio> 2 #include <algorithm> 3 #include <climits> 4 using namespace std; 5 #define MAXN 100000+10 6 7 struct Line 8 { 9 int l, r; 10 }; 11 12 Line line[MAXN]; 13 int selected[MAXN]; 14 15 bool cmp(const Line a, const Line b) 16 { 17 if (a.l != b.l) return a.l < b.l; 18 return a.r < b.r; 19 } 20 21 int main() 22 { 23 #ifdef LOCAL 24 freopen("in", "r", stdin); 25 freopen("out", "w", stdout); 26 #endif 27 int N; 28 scanf("%d", &N); 29 while (N--) 30 { 31 int m; 32 scanf("%d", &m); 33 int n = 0; // the number of lines 34 while (1) 35 { 36 scanf("%d%d", &line[n].l, &line[n].r); 37 if (line[n].l == 0 && line[n].r == 0) break; 38 n++; 39 } 40 sort(line, line+n, cmp); 41 int p = 0; 42 int start, end = 0; 43 int ans = 0; 44 bool ok = true; 45 while (end < m) 46 { 47 start = end; 48 int q = p; 49 int upper = INT_MIN; // the upper bound of interval whose lower bound <= "start" and upper bound is upperest 50 int t; 51 while (p < n && line[p].l <= start) 52 { 53 if (line[p].r > upper) 54 { 55 upper = line[p].r; 56 t = p; 57 } 58 p++; 59 } 60 if (p == q || upper <= start) // if p=q, thers isn't line whose left end is less than start, thus can cover 61 { 62 ok = false; 63 break; 64 } 65 end = upper; 66 selected[ans] = t; 67 ans++; 68 } 69 if (ok) 70 { 71 printf("%d\n", ans); 72 for (int i = 0; i < ans; i++) 73 printf("%d %d\n", line[selected[i]].l, line[selected[i]].r); 74 } 75 else printf("0\n"); 76 if (N) printf("\n"); 77 } 78 return 0; 79 }
其中p=q时说明剩下的线段中最小线段的起点>start,无解;upper <= start是说明裁剪线段后没有剩下线段了,无解。
今天看了点别人的博客,看来要想在acm上有点长进,全力投入一段时间是必须的,不能再走马观花似的那样三心二意了。然后就是,其实很早就发现了,现在还停留在别人二年或者三年前的水平,都快毕业的人了...无地自容啊,大牛就更不敢比了,唉,要好好努力了