zsc1567: 烦恼的小明&hdu 1007(分治)

来源:互联网 发布:石头剪刀布 网络歌手 编辑:程序博客网 时间:2024/06/11 06:02


1567: 烦恼的小明

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 115  Solved: 6
[Submit][Status][Web Board]

Description

A市政府2015年拿到了一笔教育资金,于是想建一所中学和一个图书馆。作为此项工程的策划工程师,小明要在A市n块空地上选两块来建中学和图书馆。曾经也是一个学霸的小明,深知图书馆对一个学霸来说是多么重要的地方,于是小明想在这n块空地上找两块来建中学和图书馆,使得它们的距离最近,算出大概需要步行多久,步行速度约为1.5m/s。可是此项工程还有许多别的难题要解决,于是小明寻求聪明的你来帮他解决这个问题。

Input

输入有多组数据。每一组数据第一行输入n(2<=n<=100000),表示有n块空地。接下来n行,每行为每一块空地的坐标x和y(x和y均为double型,-1000.0<=x,y<=1000.0)。注意:可能出现n块地中有重复坐标的,中学和图书馆允许在同一坐标(当该坐标出现2次及以上时)。当n为0时结束。

Output

每一组数据输出步行所需要的时间(s),保留两位小数。

Sample Input

2
0 0
2 2
3
1.6 -1
5 7
-1 9
3
0 0
0 0
1 1
0

Sample Output

1.89
4.22
0.00



这个题目其实就是hdu1007的原题目,这里涉及到了一个叫做最近点对的算法,这题暴力很明显是会TLE的,所以要优化。而这里的优化可以用分治法胡乱一波。其实这个算法就是说在x轴中排好序后,模拟一棵树,就是分治。不断缩小范围,直到剩下两个或三个节点就返回(代码有解释),之后再存起在【mid-ans,mid+ans】的节点,然后再在y轴排序。之后逐个求距离。之所以这种方法可行是因为ans的缘故,将范围收窄在了mid的左右。
参考资料:
http://blog.csdn.net/hackbuteer1/article/details/7482232
http://blog.csdn.net/liufeng_king/article/details/8484284

AC代码:


#include<iostream>#include<functional>#include<algorithm>#include<cstring>#include<string>#include<vector>#include<cstdio>#include<cmath>#include<map>using namespace std;#define CRL(a) memset(a,0,sizeof(a))#define QWQ ios::sync_with_stdio(0)typedef unsigned long long LL;typedef  long long ll;const int T = 100000+50;const int mod = 1000000007;struct node{double x,y;}a[T],b[T];bool cmp(const node& a,const node& b){    return a.x<b.x; }bool Cmp(const node& a,const node& b){    return a.y<b.y; }double dis(const node& a,const node& b)//欧几里得距离{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double DFS(int L,int R)//分治{if(L+1==R)//两个点时return dis(a[L],a[R]);if(L+2==R)//当分到只剩三个点时,不能再分了,不然有一边不能组成线段return min(dis(a[L],a[R]),min(dis(a[L],a[L+1]),dis(a[L+1],a[R])));int mid = (L+R)>>1;double ans = min(DFS(L,mid),DFS(mid+1,R));int c=0;for(int i=L;i<=R;++i){if(a[i].x>=a[mid].x-ans&&a[i].x<=a[mid].x+ans)//找出在【-ans,ans】的范围内的点才有可能组合出比ans小的线段b[c++] = a[i];}sort(b,b+c,Cmp);for(int i=0;i<c;++i){for(int j=i+1;j<c;++j){if(b[j].y-b[i].y>=ans)break;//只要是距离大于ans就直接退出,因为已经找不到更小的线段了ans =min(ans,dis(b[i],b[j]));}}return ans;}int main(){#ifdef zsc    freopen("input.txt","r",stdin);#endif    int i,j,k,n,t;    while(scanf("%d",&n),n)    {for(i=0;i<n;++i){scanf("%lf%lf",&a[i].x,&a[i].y);}sort(a,a+n,cmp);printf("%.2lf\n",DFS(0,n-1)/1.5);    }    return 0;}


0 0
原创粉丝点击