本题大意: 给定一个定区间[m,n], 再给出一系列的区间[Ai, Bi] 求出最少需要几个区间[Ai,Bi] 组合起来才能覆盖定区间[m,n]
解题思路: 这种区间问题,可以用贪心算法来求解,为了优化时间复杂度。我们在输入数据时进行预处理、把那些Ai>=m或者Bi<=n的区间去掉。在处理区间时,先进行排序,排序的好处就是加快后面的贪心算法时获取最优解得速度。当然不用也没问题。
Ac代码如下:(cmp函数可以简化,不用判断左值是否相等也是没问题的,个人习惯而已)
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100000+100;
struct Node {
int l;
int r;
}list[MAXN], ans[MAXN];
int cmp(const void*p1, const void * p2) {
Node n1 = *(Node*)p1;
Node n2 = *(Node*)p2;
if (n1.l!=n2.l)
return n1.l - n2.l;
return n1.r - n2.r;
}
void solve(int nCnt, int left, int right) {
// 先进行一次排序 加快贪心获取速度
qsort(list, nCnt, sizeof(list[0]), cmp);
int rCnt = 0;// 结果个数
// 采用贪心算法 每次获取r值最大且满足l<=0的
int rMax = left;
bool find; // 用来记录每一次轮循是否成功找到“最优解”
int index =0; // 记录上一次找到的最优解得下标 (加快查找速度)
for (;;) {
find = false;
for (int i = index; i< nCnt; ++i) {
if (list[i].l<=left && list[i].r> rMax) {
rMax = list[i].r;
index = i;
find = true;
}
}
// 如果找到最优解 更新左值范围 并把找到的点记录到结果里面
if (find) {
left = list[index].r;
ans[rCnt++] = list[index++];
if (list[index-1].r>= right) {
cout<< rCnt<< endl;
for (int i =0; i< rCnt; ++i)
cout<<ans[i].l<<" "<< ans[i].r<<endl;;
return;
}
} else {
// 输出结果
cout<<0<<endl;
return ;
}
}
}
int main() {
int t;
cin>>t;
while (t--) {
int k ;
cin>>k;
int l, r;
int nCur= 0; // 表示当前共获取了几个节点
while (scanf("%d%d", &l, &r)) {
if (!l && !r)
break;
if (l>=k || r<=0) // 进行预处理
continue;
list[nCur].l = l;
list[nCur++].r = r;
}
solve(nCur,0, k);
if (t)
cout<<endl;
}
return 0;
}