Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 42925 | Accepted: 9485 |
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
Source
题目链接:http://poj.org/problem?id=1328
题意:有一条直的海岸线,上面有雷达。以海岸线为x轴,x轴上面为海,下面为岸。海里面有很多岛屿。已知雷达的观测半径。问最少建多少个雷达能把所有岛屿都覆盖到雷达
的侦测范围内。如果不能覆盖全部的岛屿,按样例输出Case数和-1,反之输出Case数和最少需要建立的雷达数。
分析:首先算出经过每个雷达且平行于x轴的弦:假设雷达覆盖半径为d。则弦的左端点为x-sqrt (d*d-y*y),右端点为x+sqrt(d*d-y*y)。然后按左端点从小到大排序。由于不能受右
端点的影响,将弦的左右端点横坐标用结构体存起来。然后,将第一个雷达放在排序后的弦投影在x轴的右端点temp。从过第2个岛屿的弦的投影开始扫描,如果右端点
<temp即右端点在雷达左边。把雷达移动到此右端点,此时就能使雷达既覆盖到这个岛屿,又覆盖到前面的岛屿。如果左端点在雷达右边,则不能覆盖,需要再建立一个
雷达。然后把新雷达建在此时弦右端点投影到x轴的坐标。忽略前面的,对后面的岛屿进行同样的操作。(贪心思想)
注意:半径和坐标都有可能是小数,所以用double类型比较好,不然用int又要注意计算时*1.000变为浮点数。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; struct point { double left; double right; }p[5012]; bool flag; int cnt; bool cmp(point &x,point &y) { return x.left<y.left; } int main() { int cases=0,i,n; double d; while(scanf("%d%lf",&n,&d)&&n&&d) { flag=true; double a,b; for(i=0;i<n;i++) { scanf("%lf%lf",&a,&b); if(fabs(b)>d) flag=false; p[i].left=a-sqrt(d*d-b*b); p[i].right=a+sqrt(d*d-b*b); } printf("Case %d: ",++cases); if(!flag) puts("-1"); else { sort(p,p+n,cmp); double temp=p[0].right; cnt=1; for(i=1;i<n;i++) { if(p[i].right<temp) temp=p[i].right; else if(p[i].left>temp) { cnt++; temp=p[i].right; } } printf("%d\n",cnt); } } return 0; } //AC
11920732 |
Accepted |
188K |
32MS |
981B |
2013-08-05 00:20:15 |