题干:
We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.
Figure A Sample Input of Radar Installations
The input is terminated by a line containing pair of zeros
3 2 1 2 -3 1 2 11 2 0 20 0Sample Output
Case 1: 2 Case 2: 1
题目大意:
在x轴上建造雷达,似的x轴上方的所有岛屿都能被辐射到。每个雷达的辐射半径已知,求:为使所有岛屿都被辐射到,所需要的最少雷达个数。
解题报告:
这应该说是我遇到的第二个不算很水的计算几何问题,上一个是 解救雅典娜,用dp做,这一题是用贪心做。先按照x坐标从小到大排序,先确定一个半完成值(half-finish自己取的名,第一次使用是在这里)圆心setx,然后逐个遍历圆心curx(这里取右圆心)(因为圆的半径已知为d,所以圆心的x轴坐标显然可求),如果curx<=setx 显然要取curx 为圆心的那个圆,因为这样两个岛屿都会被包进去。如果curx>setx 那就要比较一下该点到圆心setx的距离是否大于d,如果小于等于d,那虚惊一场可以辐射到这个岛,如果大于d,那凉凉,只能新建一个雷达了所以ans++。遍历完所有岛屿即可得出答案ans。(但是总觉得不严谨,因为你虽然这个点(记为A)到圆心(记为setx1)的距离大于d了,你就更新了setx(更新为setx2),但有可能下一个点(记为B)满足curx>setx1&&到圆心的距离<=d呢?,所以不应该这么着急着更新setx吧,,,因为你不确定B是不是也不满足小于等于d这个要求啊)
对上面问题的回答:是这样的,确实保证不了,但是因为你已经有一个A满足不了了,所以无论如何你也要为了A岛屿而建立一个雷达,而这个新雷达能否包含B就看B这个的坐标了。。。即:题目只问的是最少需要建几个雷达,而非让你把每个岛屿属于哪个雷达说清楚,因此没必要考虑这些问题。
ac代码:
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;struct Node {int x, y;
} node[1000 + 5];bool cmp(const Node & a,const Node & b) {return a.x<b.x;//此题y坐标排不排序无所谓的、、、 }int main()
{int n,d;int ans=1;int maxy;int iCase=0;double curx,setx,seti;//curx表示当前尝试的右圆心 setx表示当前确定的右圆心 seti表示当前确定的索引值 double curd;//curd表示当前尝试的圆的半径 while(scanf("%d %d",&n,&d)) {ans=1;maxy=0;//别忘了初始化! ! if(n==0 && d==0) break;for(int i = 0; i<n; i++) {scanf("%d %d",&node[i].x,&node[i].y); maxy=max(node[i].y,maxy);}if(maxy>d) {printf("Case %d: -1\n" , ++iCase);continue;}sort(node,node+n,cmp);curx=node[0].x+sqrt(d*d-( node[0].y )*( node[0].y ) );setx=curx;seti=0;for(int i = 1; i<n; i++) {//因为第一个已经初始化好了,所以下标从1开始 curx=node[i].x+sqrt(d*d-( node[i].y )*( node[i].y ) );if(curx<=setx) {setx=curx;}else {curd=sqrt( (node[i].x-setx)*(node[i].x-setx) +(node[i].y)*(node[i].y) );if(curd<=d) {continue;}else {ans++;setx=curx;}}} printf("Case %d: %d\n",++iCase,ans);} return 0 ;
}
下面附上kuangbin大佬的代码:(其实差不多的只不过我是用的点到setx的距离d,他是用的点的左圆心)
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>//sort所在的库文件,排序用
using namespace std;
const int MAXN=1005;
struct Line
{double l,r;
}line[MAXN];//每个岛作半径为d的圆,与x轴所截的线段bool cmp(Line a,Line b)
{return a.l<b.l;
} //按照线段的左端点从小到大排序
int main()
{//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);int n,d;int i;int x,y;bool yes;//确定是不是有解int icase=1;while(cin>>n>>d){yes=true;int cnt=0;if(n==0&&d==0)break;for(i=0;i<n;i++){cin>>x>>y;if(yes==false)continue;if(y>d)yes=false;else{line[i].l=(double)x-sqrt((double)d*d-y*y);line[i].r=(double)x+sqrt((double)d*d-y*y);} }if(yes==false){cout<<"Case "<<icase++<<": -1"<<endl;continue;}sort(line,line+n,cmp);cnt++;double now=line[0].r;for(i=1;i<n;i++){if(line[i].r<now)//这点很重要 now=line[i].r;else if(now<line[i].l){now=line[i].r;cnt++;} }cout<<"Case "<<icase++<<": "<<cnt<<endl; } return 0;
}