Description
给定 n 个平面上的点,求最近两个点的编号。
Input
每组数据第一行 2 ≤ n ≤ 10^5,接下来 n 行每行两个整数 0 ≤ xi, yi ≤ 10^4, i = 0, 1, 2, ⋯, n − 1,表示第i个点的坐标。
Output
输出最近两个点的编号 a 和 b,按 a < b 输出。如果有多个答案,输出 a 最小的,如果依然有多个答案,在这些答案里输出 b 最小的。
Sample Input
3
0 0
1 1
3 3
Sample Output
0 1
该题属于算法实验分治练习中的题目,还是利用分治的思想解决
首先,我们还是将问题分割成一个一个的规模较小的问题,这里容易想到,规模最小的问题就是当我们已经将所有点分割到只剩两个点了,那么此时最近两个点的就是这两个点了,再考虑正常情况下,我们肯定会将所有点分割成两边各自求问题(分治思想),那么最近的两个点可能会出现在哪里呢,这里也比较容易想到的是两个点都出现在分割后的左边、都出现在分割后的右边,一个在左一个在右,那么问题的答案很明显就是在这三种情况中取一种即可
那么前两种情况比较容易计算,按照上面的(将所有点分割到只剩两个点了)递归计算即可(将二者的较小值设为ans),主要考虑一个在左和一个在右,我们不可能遍历两边所有的点进行计算的,因此这里需要一些优化,这里读者可画图理解,我们取最中间的点作一条中垂线,然后我们通过ans来筛选出可能出现更小值的点进行计算,只有那些到中垂线距离小于ans的点才有可能出现更小距离,因为如果横向距离的都超过ans了那肯定不可能小于ans啦,同理对于y轴上也是如此
分析到这里我们就可以写代码了
#include<cstdio> #include<cmath> #include<algorithm> #include<climits> using namespace std; const int MAX=1e5+10; const int INF = 2 << 20; typedef struct Node{ double x,y; int id; }Node; int n; Node arr[MAX]; int temp[MAX]; int ans1=2147483647,ans2=2147483647;//序号 double len=2147483647;//最小距离 bool cmp(const Node &a, const Node &b) { if(a.x == b.x) return a.y < b.y;//按照x排序 else return a.x < b.x; } void updatee(int id1,int id2,double cur){ if(id1>id2){//保证序号顺序 int temp=id1; id1=id2; id2=temp; } if(cur!=len){//更新序号和最小距离 ans1=id1; ans2=id2; len=cur; }else{ if(id1<ans1||(id1==ans1&&id2<ans2)){//距离相等情况下按照序号更新 ans1=id1; ans2=id2; } } } double dis(int left,int right){ double a=(arr[right].x-arr[left].x)*(arr[right].x-arr[left].x); double b=(arr[right].y-arr[left].y)*(arr[right].y-arr[left].y); return sqrt(a+b); } void fun(int left,int right){ if(left==right){ return ; } if(right-left==1){ double cur=dis(left,right); if(cur<=len){//注意距离相等情况下也要进函数 updatee(arr[left].id,arr[right].id,cur); } return ; } int mid=(left+right)/2; fun(left,mid);//左区间 fun(mid+1,right);//右区间 //还有中间区间 int k=0; for(int i=left;i<=right;i++){ if(fabs(arr[i].x-arr[mid].x)<=len){ temp[k++]=i; } } for(int i=0;i<k;i++){ for(int j=i+1;j<k;j++){ double s=dis(temp[i],temp[j]); if(s<=len){//注意距离相等情况下也要进函数 updatee(arr[temp[i]].id,arr[temp[j]].id,s); } } } } int main(){ scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%lf%lf",&arr[i].x,&arr[i].y); arr[i].id=i; } sort(arr,arr+n,cmp);//排序方便取出中间值 fun(0,n-1); // printf("%.4lf\n",len); printf("%d %d\n",ans1,ans2); return 0; }