1 #include <cmath> 2 #include <algorithm> 3 #include <iostream> 4 #include <string.h> 5 using namespace std; 6 struct node 7 { 8 double x,y; 9 }a[100005]; 10 int c[100005]; 11 double cmpy(int t1,int t2) //对照函数:比较y的大小,用于排序 12 { 13 return a[t1].y<a[t2].y; 14 } 15 bool cmp(node t1,node t2) //比较x坐标的大小 16 { 17 return t1.x<t2.x; 18 } 19 double dis(node t1,node t2) //计算两点距离 20 { 21 return sqrt((t1.x-t2.x)*(t1.x-t2.x)+(t1.y-t2.y)*(t1.y-t2.y)); 22 } 23 double min(double t1,double t2) //比较两数大小,返回小者 24 { 25 return t1<t2?t1:t2; 26 } 27 double find(int left,int right) 28 { 29 if(left+1==right) //只剩2个点的情况 30 return dis(a[left],a[right]); 31 if(left+2==right) //只剩3个点的情况 32 return min(dis(a[left],a[right]),min(dis(a[left],a[left+1]),dis(a[left+1],a[right]))); 33 34 int mid=(left+right)>>1; //二分 35 double ans=min(find(left,mid),find(mid+1,right)); //两分递归 36 int i,j,cnt=0; 37 for(i=left;i<=right;i++) //列出mid-ans,mid+ans区间内的所有点,记在C数组中 38 if(a[i].x >= a[mid].x-ans && a[i].x <= a[mid].x+ans ) 39 c[cnt++]=i; 40 sort(c,c+cnt,cmpy); //按y来排序 41 for(i=0;i<cnt;i++) //计算mid-ans,mid+ans区间内的所有点之间的距离,求最小 42 for(j=i+1;j<cnt;j++) 43 { 44 if(a[c[j]].y-a[c[i]].y>=ans) //若两点的Y距离已超过ans,那么无需计算c数组后面那些了 45 break; 46 ans=min(ans,dis(a[c[i]],a[c[j]])); //求最小距离 47 } 48 return ans; 49 } 50 51 int main() 52 { 53 int n,i; 54 while(cin>>n,n) 55 { 56 for(i=0;i<n;i++) //接收输入 57 { 58 cin>>a[i].x>>a[i].y; 59 } 60 std::sort(a,a+n,cmp); //先按X排序 61 printf("%.2lf\n",find(0,n-1)/2); //调用算法,直接输出 62 } 63 return 0; 64 }
上面那个代码是别人的,拿来参考了下。
下面这个稍微修改了一点,但是执行时间没有加快。实在想不到怎么加速了。
1 #include <cmath> 2 #include <algorithm> 3 #include <iostream> 4 #include <string.h> 5 using namespace std; 6 struct node 7 { 8 double x,y; 9 }a[100005]; 10 int c[100005]; 11 double cmpy(int t1,int t2) //对照函数:比较y的大小,用于排序 12 { 13 return a[t1].y<a[t2].y; 14 } 15 bool cmp(node t1,node t2) //比较x坐标的大小 16 { 17 return t1.x<t2.x; 18 } 19 double dis(node t1,node t2) //计算两点距离 20 { 21 return sqrt((t1.x-t2.x)*(t1.x-t2.x)+(t1.y-t2.y)*(t1.y-t2.y)); 22 } 23 double min(double t1,double t2) //比较两数大小,返回小者 24 { 25 return t1<t2?t1:t2; 26 } 27 28 double find(int left,int right) 29 { 30 if(left+1==right) //只剩2个点的情况 31 return dis(a[left],a[right]); 32 if(left+2==right) //只剩3个点的情况 33 return min(dis(a[left],a[right]),min(dis(a[left],a[left+1]),dis(a[left+1],a[right]))); 34 35 int mid=(left+right)>>1; //二分 36 double ans=min(find(left,mid),find(mid+1,right)); //两分递归 37 int i,j,cnt=0,ctl=0; 38 for(i=mid;i>=left;i--) //列出mid-ans,mid+ans区间内的所有点,记在C数组中 39 if(a[i].x >= a[mid].x-ans ) 40 c[cnt++]=i; 41 else 42 break; 43 for(i=mid+1;i<=right;i++) //列出mid-ans,mid+ans区间内的所有点,记在C数组中 44 if(a[i].x <= a[mid].x+ans ) 45 c[cnt++]=i; 46 else 47 break; 48 sort(c,c+cnt,cmpy); //按y来排序 49 for(i=0;i<cnt;i++) //计算mid-ans,mid+ans区间内的所有点之间的距离,求最小 50 for(j=i+1;j<cnt;j++) 51 { 52 if(a[c[j]].y-a[c[i]].y>=ans) //若两点的Y距离已超过ans,那么无需计算c数组后面那些了 53 break; 54 if(a[c[i]].x<=a[mid].x&&a[c[j]].x>=a[mid].x || a[c[i]].x>=a[mid].x&&a[c[j]].x<=a[mid].x) 55 ans=min(ans,dis(a[c[i]],a[c[j]])); //求最小距离 56 } 57 return ans; 58 } 59 60 int main() 61 { 62 int n,i; 63 while(cin>>n,n) 64 { 65 for(i=0;i<n;i++) //接收输入 66 { 67 cin>>a[i].x>>a[i].y; 68 } 69 std::sort(a,a+n,cmp); //先按X排序 70 printf("%.2lf\n",find(0,n-1)/2); //调用算法,直接输出 71 } 72 return 0; 73 }
思路:分治,先排序,用2分,直到剩下两或三个点,直接计算。需要注意处理两个域内的中间部分,可能一个点在左边,一个点在右边。如果左边的一个点到达中线的距离已经超过各自一边单独的最短距离,那么这个点到达右边任意一个点也不会是最短距离了。同时,若两个点的y距离已经超过目前最短距离,那么也不可能是最短距离,因此,还得在x距离满足的情况下,y也得满足,所以y也得排序。
错误:我试过不用分治的,稍微暴力的,但是还是TLE,哎。。 大概思路是:先随便求出两点的距离,作为当前最小距离ans;接着每个点需要扫一次,每次都以ans为半径,以该点为圆心作一个圆,仅计算该点到圆内的其他点的距离,然后更新ans;到最后的半径应该越来越短,需要计算的也就越少。
如何再把时间缩短呢?