标签:贪心
Description
Input
Output
Sample Input
3 2 1 2 -3 1 2 1 1 2 0 2 0 0
Sample Output
Case 1: 2 Case 2: 1
这题用的是贪心思想,对于每个小岛,可以在x轴上面把可以覆盖到此岛的区间算出来,即[x-sqrt(d*d-y*y),x+sqrt(d*d-y*y)],可以先对所有区间线段按右端点升序排序,然后依次找到最小的右端点,找到后所有左端点小于此右端点的记录一个标记b[i].vis=1,代表这条线段已经有点,往后就不用找了。这题也可以用另一种思路,所有区间线段按照左端点进行降序排序,初始的右端点记为s=b[1].r,如果后面的线段的左端点的值大于s,那么要加一个地雷点,且s=b[i].r,如果线段的右端点小于s,那么更新s=b[i].r.两种思路的本质其实是一样的。
思路一:
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; struct node { double l,r; int vis; }b[1005]; bool cmp(node a,node b) { double temp; if(a.r>b.r){ temp=b.l;b.l=a.l;a.l=temp; return a.r<b.r; } return a.r<b.r; } int main() { double d,x,y; int i,j,n,num,m=0,flag; while(scanf("%d%lf",&n,&d)!=EOF) { m++; if(n==0 && d==0)break; flag=1; memset(b,0,sizeof(b)); for(i=1;i<=n;i++){ scanf("%lf%lf",&x,&y); if(y>d){ flag=0; //这里不要用break,因为数据还要输进去的。 } b[i].l=x-sqrt(d*d-y*y); b[i].r=x+sqrt(d*d-y*y); } if(flag==0){ printf("Case %d: -1\n",m);continue; } sort(b+1,b+1+n,cmp); num=0; for(i=1;i<=n;i++){ if(b[i].vis==0){ num++;b[i].vis=1; for(j=1;j<=n;j++){ if(b[j].l<=b[i].r){ b[j].vis=1; } } } } printf("Case %d: %d\n",m,num); } return 0; }
思路二:
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; struct node { double l,r; }b[1005]; bool cmp(node a,node b) { double temp; if(a.l>b.l){ temp=b.r;b.r=a.r;a.r=temp; return a.l<b.l; } return a.l<b.l; } int main() { double d,x,y,s; int i,j,n,num,m=0,flag; while(scanf("%d%lf",&n,&d)!=EOF) { m++; if(n==0 && d==0)break; flag=1; memset(b,0,sizeof(b)); for(i=1;i<=n;i++){ scanf("%lf%lf",&x,&y); if(y>d){ flag=0; } b[i].l=x-sqrt((double)(d*d-y*y)); b[i].r=x+sqrt((double)(d*d-y*y)); } if(flag==0){ printf("Case %d: -1\n",m);continue; } sort(b+1,b+1+n,cmp); num=1; s=b[1].r; for(i=2;i<=n;i++){ if(b[i].l>s){ num++; s=b[i].r;continue; } if(b[i].r<s){ s=b[i].r; continue; } } printf("Case %d: %d\n",m,num); } return 0; }
标签:贪心
原文地址:http://blog.csdn.net/kirito_acmer/article/details/45419713