题目链接:点击打开链接
题目大意:先确定一个M, 然后输入 x 组线段的左端和右端,然后让你求出来在所给的线段中能够把【0 ~ M】
区域完全覆盖完的最少需要的线段数,并输出这些线段的左右端点
解题思路: 很经典的贪心求最小覆盖的问题,精华部分在于左右端点的变换,不要弄乱了,可以模拟一下,便于理解
具体过程如下:首先对所有的线段按照左端点的位置排序,以要覆盖区间的左端点为开始,然后开始寻找左边小于等于这个要求值,右边大于右侧变化值(开始时左右值相等,然后开始寻找!!!!不断更新右侧的值,因为贪心嘛,想覆盖尽量多的区域)的线段,更新左侧的值,遍历一遍之后记录一下此次遍历覆盖区域最大的那条线段的标号,然后存储起来,然后更新右值(也就是遍历得到的最大的左值),如此循环,知道得到的左值大于M。
代码:
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
class Line
{
public:
int left, right;
Line():left(0), right(0) {}
Line(int l, int r): left(l), right(r) {}
};
Line line[100010];
Line need[100010];
bool cmp(Line l1, Line l2)
{
if(l1.left < l2.left)
return true;
else
return false;
}
int T, M, n;
int solve()
{
if(line[0].left > 0)
return 0;
int rr = 0;
int t = 0;
while(rr < M)
{
int I;
int ll = rr;
for(int i = 0; i < n; i++)
{
if(line[i].left <= rr && line[i].right > ll)
{
I = i;
ll = line[i].right;
}
}
//cout << mi << " *** " << temp << endl;
if(rr == ll)
{
t = 0;
break;
}
need[t].left = line[I].left; need[t].right = line[I].right;
t++;
rr = ll;
}
return t;
}
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d", &M);
int a, b;
n = 0;
while(scanf("%d %d", &a, &b))
{
if(a == 0 && b == 0)
break;
line[n].left = a; line[n].right = b;
n++;
}
sort(line, line+n, cmp);
int ans = solve();
if(ans == 0)
printf("%d\n", ans);
else
{
printf("%d\n",ans);
for(int i = 0; i < ans; i++)
{printf("%d %d\n", need[i].left, need[i].right);
// if(i != ans-1) printf("\n");
}
}
if(T != 0)
printf("\n");
}
return 0;
}