区间覆盖的问题。给定n个区间,覆盖[0,M],要求覆盖数最小。
采用贪心的做法。先预处理一次,左端点<0的可以直接看做从0开始,右端点<0的直接忽略掉。
设当前所覆盖的是current_l,一开始是0.从0开始处理。
因为已经对数组进行排序,若segment[0].x>0的话一定没有覆盖的。
所以开始处理的时候则第一个左端点一定是0。后面就找到最长的右端点current_r。
然后就改current_l =最长的右端点,然后在对所有左端点小于current_l的端点像一开始预处理一样,把左边的端点变为 current_l。一直到current_r >=M的时候就可以跳出循环了。
然后每次都保存一次路径。
AC代码:
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int MAX_NUMBER = 100006; struct node{ int l; int r; }segment[MAX_NUMBER]; node del_segment[MAX_NUMBER]; int path[MAX_NUMBER]; bool cmp(node a,node b){ if (a.l < b.l) return true; else return false; } int main() { int test_case; cin >> test_case; cin.get(); while (test_case--) { int M; int numbers; int max_right = 0; cin >> M; for (int i = 0; i < MAX_NUMBER; i++) { cin >> segment[i].l; cin >> segment[i].r; if (segment[i].r > max_right) max_right = segment[i].r; if (!segment[i].l && !segment[i].r) { numbers = i; break; } if (segment[i].r <= 0) i--; } sort(segment,segment+numbers,cmp); memcpy(del_segment,segment,sizeof(segment)); for (int i = 0; i < numbers; i++) { if (segment[i].l < 0) segment[i].l = 0; } if (segment[0].l > 0 || max_right < M) { cout << 0 << endl; if (test_case){ cout << endl; } continue; } int current_l = 0; int current_r = 0; int j,k = 0, flag; int left = 0,now_path = 0; int has_not_found = 0; while (1) { for (j = left; j < numbers && segment[j].l <= current_l; j++) { if (segment[j].r > current_r){ current_r = segment[j].r; path[now_path] = j; } } now_path++; current_l = current_r; if (current_r >= M) break; flag= 1; for (k = j; segment[k].l <= current_l; k++) { if (segment[k].r > current_l) { segment[k].l = current_l; if (flag) { flag = 0; left = k; } } } if (flag) { has_not_found = 1; break; } } if (has_not_found) { cout << 0 << endl; if (test_case) { cout << endl; } continue; } cout << now_path << endl; for (int i = 0;i < now_path; i++) { cout << del_segment[path[i]].l << " " << del_segment[path[i]].r; cout << endl; } if (test_case) cout << endl; } return 0; }