区间覆盖的问题。给定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;
}