题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1007
题意:在平面上给你很多点,任意两点之间的最短距离。
分析:
一眼看到这个题想到暴力,二重循环,然后一看数据范围果断放弃,然后在网上查了一下就有一个方法可以在nlog(n)的方法求出,分治的思想,我现在听过分治就只在分治排序的那里听过。这个算法的原理是我们先对点进行按x大小进行排序,然后找出x的中位数(mid)在中位数的两边大概会有n/2个点,这个最近的点的距离(两个点)只会在mid左边,或者在mid的右边,最麻烦的可能是一个点在mid的左边另一个在mid的右边。这个算法的难点也在此,mid左边会得到一个最小值 ans1,右边最小值ans2,ans=min(ans1,ans2),如果在mid的两边的点会产生最小距离,则可能产生这些点x是会有一个范围的,mid左右两边扩展ans,得到如下图(别人的 嘿嘿)
然后在通过一个证明,证明太麻烦跳过了,可以得到要满足mid左边的一个和mid右边得一个点构成得距离小于ans,则一个左边的点最多对应右边6个点(可能说的不清楚,但是要说清楚很麻烦,很烦)要想彻底搞懂这个题可以去看看别人得博客 我很菜。
代码:模板吧
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
struct node {
double x;
double y;
}p[100050];
int a[100050];
bool cmpx(node qq,node ww)
{
return qq.x<ww.x; //小到大
}
bool cmpy(int qq,int ww)
{
return p[qq].y<p[ww].y; //小到大
}
double dis(node qq,node zz)
{
return sqrt(((qq.x-zz.x)*(qq.x-zz.x))+((qq.y-zz.y)*(qq.y-zz.y)));
}
double find1(int l,int r)
{
if(l+1==r) return dis(p[l],p[r]);
if(l+2==r) return min(min(dis(p[l],p[l+1]),dis(p[l+1],p[r])),dis(p[l],p[r]));
int mid=(l+r)/2;
double ans;
ans=min(find1(l,mid),find1(mid+1,r));
int cnt=0;
for (int i=l;i<=r;i++)
if(p[i].x>=p[mid].x-ans&&p[i].x<=p[mid].x+ans)
a[cnt++]=i;
sort(a,a+cnt,cmpy);
for (int i=0;i<cnt;i++)
{
for (int j=i+1;j<cnt&&j<i+7;j++)
{
ans=min(ans,dis(p[a[i]],p[a[j]]));
}
}
return ans;
}
int main ()
{
int n;
while (scanf ("%d",&n)&&n)
{
for (int i=0;i<n;i++)
scanf ("%lf %lf",&p[i].x,&p[i].y);
sort(p,p+n,cmpx);
//for (int i=0;i<n;i++)
// printf ("%lf %lf\n",p[i].x,p[i].y);
printf ("%.2lf\n",find1(0,n-1)/2.0);
}
return 0;
}