http://acm.timus.ru/problem.aspx?space=1&num=1303
题目大意
读入一个整数m(1<=m<=5000)。 接下来若干行,表示若干条线段。 从l[i]到r[i](最多100000条线段)。 到一行0 0为止。 求最少要用多少条线段可以覆盖区间[0,m]。 输出第一行一个数字,表示最少线段数。 接下来若干行表示选择的线段。按照顺序!!!注意:这里的按照顺序不是指线段输入的顺序而是每条线段的左右点的顺序 若无解则输出'No solution'。
题目的意思理解之后,不难确定选择贪心算法。
为了是线段用得最少,而且完全覆盖住0~m区间,我们只需要从左往右超就行了。
如果一个线段的右端点比0还小,显然不需要考虑他。同理么,每次设置一个temp值,表示新的起点,就能够把这个题目解出。
只要左端点比当前的起点要小,找出他们的最大值,使最大值为新的起点,(赋为temp值),。然后接着如此循环,直到temp大于m就行
方法很简单,代码如下:
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define M 600010
#define mem0(f) memset(f,0,sizeof(f))
struct lines
{
int left;
int right;
}line[M];
bool cmp(lines a,lines b)
{
return a.left<b.left;
}
int m;
int xuhao[M]={0};//记录选择的线段的序号
int main()
{
freopen("in.txt","r",stdin);
int i=0;
scanf("%d",&m);
while(1)
{
scanf("%d%d",&line[i].left,&line[i].right);
if(!line[i].left&&!line[i].right)break;
i++;
}
sort(line,line+i,cmp);
int temp=0;
int maxx=0;
int c=0;
int k,z=0;
while(temp<m)
{
for(k=z;line[k].left<=temp;k++)
{
if(line[k].right>maxx)
{
maxx=line[k].right;
xuhao[c]=k;
}
}
if(k==z)
{
printf("No solution
");
return 0;
}
temp=maxx;
z=k;
c++;
if(k>=i)break;
}
if(temp<m)printf("No solution
");
else
{
printf("%d
",c);
for(int p=0;p<c;p++)
{
printf("%d %d
",line[xuhao[p]].left,line[xuhao[p]].right);
}
}
return 0;
}
这个代码据目前检测是没有问题的,从算法和做的上十组样例运算来说,是没有问题的。、
但是,在原oj上面提交竟然不过!
看了一下别人的博客,发现有些大神这个题也没有过,同样表示疑问,于是心里好受点了~~
分析一下,这个题目是有bug的:也许这是很多人不能AC的原因吧!
题目说明中并没有交待线段端点的一同情况,也就是说存在下面的情况
6
0 2
2 6
2 7
像这样的话输出结果并没有明显规定,那么输出2 6还是2 7,因为题目没有显示特判,也就是不存在多解的情况,那么肯定有一个会WA!
另外的多解情况如下:
6
-1 2
2 4
4 6
-1 3
2 5
5 7
这样的话,就不仅仅多一个解,可是题目没有说清输出的要求,所以应该就有一批人AC不了了。
以上看法,是本人的愚昧之见,如果有不对的地方请大家指出,在此感谢!
最后附上,一个AC的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 100000+10; 7 8 struct Line{ 9 int left,right; 10 }line[maxn], ans[maxn]; 11 12 bool cmp(Line L1, Line L2) //从左到右排序,覆盖掉被其他线包含的线 13 { 14 if(L1.left != L2.left) return L1.left < L2.left; 15 else return L1.right >= L2.right; 16 } 17 18 int main() 19 { 20 //freopen("in.txt","r",stdin); 21 freopen("out.txt","w",stdout); 22 int m; 23 while(scanf("%d", &m) != EOF) 24 { 25 int left,right; 26 int n = 0; 27 for(;;) 28 { 29 scanf("%d%d", &left,&right); 30 if(left == 0 && right == 0) break; 31 line[++n].left = left; 32 line[n].right = right; 33 } 34 sort(line+1, line+n+1, cmp); 35 36 int num = 1; 37 for(int i = 2; i <= n; i++) //覆盖过程 38 { 39 if(line[i].left > line[num].left && line[i].right > line[num].right) 40 line[++num] = line[i]; 41 } 42 43 n = num; 44 line[n+1].left = line[n+1].right = m+1; //边界处理 45 int cover = 0; //当前要求覆盖的点 46 int total = 0; //当前选中了的线 47 for(int i = 1; i <= n; i++) 48 { 49 if(line[i+1].left > cover && line[i].left <= cover) 50 { 51 ans[++total] = line[i]; 52 cover = line[i].right; 53 if(cover >= m) 54 { 55 printf("%d ", total); 56 for(int j = 1; j <= total; j++) 57 { 58 printf("%d %d ", ans[j].left, ans[j].right); 59 } 60 return 0; //退出程序 61 } 62 } 63 } 64 printf("No solution "); 65 } 66 return 0; 67 }
代码原处,请访问