您的位置:首页 > 其它

分治法-hdu_1007_Quoit Design

2016-05-11 22:49 113 查看
题目链接:点击打开链接

题目描述:

Quoit Design

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 44844    Accepted Submission(s): 11634


[align=left]Problem Description[/align]
Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded.

In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a
configuration of the field, you are supposed to find the radius of such a ring.

Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered
to be 0.

 

[align=left]Input[/align]
The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates
of a toy. The input is terminated by N = 0.

 

[align=left]Output[/align]
For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places.

 

[align=left]Sample Input[/align]

2
0 0
1 1
2
1 1
1 1
3
-1.5 0
0 0
0 1.5
0

 

[align=left]Sample Output[/align]

0.71
0.00
0.75

 

[align=left]Author[/align]
CHEN, Yue
 

[align=left]Source[/align]
ZJCPC2004  

题意:平面上有n个点(2 <= n <= 100000),现在让你求出这n个点中最短的距离的一半。

题目分析:很明显,如果暴力的话,复杂度为O(n^2)=O(10^10),会超时(不是废话吗!!!)
来看《算法设计与分析》(第二版)上是怎么说的(完全抄袭):“也就是说,将所给的平面上n个点的集合S分为2个子集S1,S2,每个子集中约有你、2个点。然后在每个子集中递归的求其最接近的点对。在这里,关键的问题时如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。但是,如果这2个点分别再S1和S2中,问题就不那么简单了。”

简单来说就是,求出ans = min(D(S1),D(S2)),这事最近点对都在S1或者都在S2中。
那么如果分别在S1和S2中,那么| p1.x-p2.x| <= 2*ans,只要把这之间的点求出来,然后寻找距离与ans比较取最小就行了。(这个赶脚解释的还行!!!)
这里用到了排序。

源代码:

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;

#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define in(a) scanf("%d",&a)
#define mm(a,b) memset(a,b,sizeof(a))
#define out(a) printf("%d")
#define MOD =1e9+7
#define ll long long
#define INF 0x3f3f3f3f
#define FOR(i,l,r) for(int i=l;i<=r;i++)
const int N = 100005;
struct point {
double x,y;
};
point p1
,p2
;
int cnt;
int cmpx(point a,point b){
return a.x<b.x;
}

int cmpy(point a,point b){
return a.y<b.y;
}

double dist(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double Min(int s,int e){
if(e==s+1)
return dist(p1[s],p1[e]);
if(e==s+2)
return min(dist(p1[s],p1[s+1]),min(dist(p1[s],p1[e]),dist(p1[s+1],p1[e])));
int mid=(e+s)/2;
double ans = min(Min(s,mid),Min(mid+1,e));
cnt=0;
for(int i=s;i<=e;i++){
if(p1[i].x>=p1[mid].x-ans && p1[i].x<=p1[mid].x+ans)
p2[cnt++]=p1[i];
}
sort(p2,p2+cnt,cmpy);
for(int i=0;i<cnt;i++){
for(int j=i+1;j<cnt;j++){
if(p2[j].y-p2[i].y>=ans)
break;
ans = min(ans,dist(p2[i],p2[j]));
}
}
return ans;
}
int main(){
int n;
while(~scanf("%d",&n)){
if(n==0)break;
for(int i=0;i<n;i++)
scanf("%lf%lf",&p1[i].x,&p1[i].y);
sort(p1,p1+n,cmpx);
double ans = Min(0,n-1);
printf("%.2lf\n",ans/2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: