题意就不说了很容易懂,说一下思路。 这道题问的是怎样放雷达使其放的雷达数目最少而能够探测到所有的岛屿,这里需要转换为求每个岛屿的能放雷达的区间的问题,。如下图
然后我们以每个区间的最右端排序,排完以后,我们定义个变量L,它表示现在已放置雷达能探测到的最左区间。我们用一个vis[]数组来标记一个岛屿是否已经能被探测到。
我们从i(i从n-1->0)开始(貌似也可以从左边开始),依次遍历之前的 每个区间 ,分三种情况,1,这个区间的最右端比L还小,则需要加一个雷达,2.这个区间的最右端比L要大,但是它的最左端比L要小,3.这个区间的最右端比L要大,其最左端也比i的L要大(既为现在能探测到区域的子区间).
1.对于第一种情况,我们要将雷达数加一,并把此区间的左端赋值给L。
2.对于第二种情况,我们现在已经放置的雷达能探测到它,不需要加雷达()
3.对于第三种情况,我们现在已经放置的雷达能探测到它,但是我们要把此区间的最左端赋值给L。
如下图,红色区域表示已经能探测到的区域
现在我们能够下出算法了,我对区间排序用的是qsort排序,这里简单的说下qsort的用法。
qsort(lend,n,sizeof(lend[0]),compare);
第一个参数表示要排序的数组,第二个参数表示的是要排序多少个数,第三个一定要是sizeof(数组的第一个元素),第四个参数是比较函数。比较函数是要自己写的,但其返回值必须是int 并且形参一定是
(const void * a,const void * b) (形参名a b可自行更改).
程序代码如下:
#include<stdio.h> #include<math.h> #include<stdlib.h> #include<string.h> #define len 1030 typedef struct Islend { double right; double left; }Islend; int compare(const void * a,const void * b) { Islend *x=(Islend *)a; Islend *y=(Islend *)b; if(x->right>y->right) return 1; else return -1; } int main() { int n,i,j; double d;//雷达区间 double x,y; int vis[len]; Islend lend[len]; int number=0; int num,flag; double l;//l表示当前所放雷达能探测到的最左区间,如果超过了最左区间 则需要加一个雷达 while(1) { number++; scanf("%d",&n); scanf("%lf",&d); if(n==0) break; flag=1;//判断是否有探测不到的区域 for(i=0;i<n;i++) { scanf("%lf",&x); scanf("%lf",&y); if(y>d) flag=0; lend[i].right=x+sqrt((double)(d*d-y*y));//岛i可放的雷达区间为 lend[i].left -lend[i].right lend[i].left=x-sqrt((double)(d*d-y*y)); } qsort(lend,n,sizeof(lend[0]),compare);//以区间右端排序 num=1; memset(vis,0,sizeof(vis)); l=lend[n-1].left; if(flag) { for(i=n-1;i>=0;i--) { for(j=i-1;j>=0;j--) { if(vis[j]==1)//如果在我们现有雷达能探测到的区域则直接跳过 break; else { double f=lend[j].right; if(f>=l)//j在现有雷达探测到的范围内 { if (lend[j].left>l)//如果是子区间 { l=lend[j].left;//这里赋值的意思是表明如果超过这个子区间的最左端则又要加一个雷达 } } else { num++; l=lend[j].left; } } vis[j]=1;//表明岛i 现在可探测到了 } } printf("Case %d: %d\n",number,num); } else printf("Case %d: -1\n",number); } return 0; }