题目描述
设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。
输入
多组测试数据,第一行为测试数据组数n(0<n≤100),每组测试数据由两个部分构成,第一部分为一个点的个数m(0<m≤1000),紧接着是m行,每行为一个点的坐标x和y,用空格隔开,(0<x,y≤100000)
输出
每组测试数据输出一行,为该组数据最近点的距离,保留4为小数。
样例输入复制
2 2 0 0 0 1 3 0 0 1 1 1 0样例输出复制
1.0000 1.0000#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> #include <time.h> #define endl '\n' #define N 200005 typedef long long ll; using namespace std; typedef struct { double x,y; }point; point p[N]; int tiaodai[N]; //对点集排序 bool cmp1(point a,point b) { if(a.x==b.x) { return a.y<b.y; } else return a.x<b.x; } bool cmp2(int a,int b) { return p[a].y<p[b].y; } double distance(int i,int j) { return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)); } double merge(int left,int right) { //递归找出左右两边的dis double dis=999999; if(left==right) return dis; if(left+1==right) { return distance(left,right); } int mid=(left+right)>>1; double dis1=merge(left,mid); double dis2=merge(mid+1,right); dis=min(dis1,dis2); //sum动态计算条带中点的个数 int sum=0; for(int i=left;i<=right;i++) { if(fabs(p[i].x-p[mid].x)<=dis) { tiaodai[++sum]=i; } } //对条带排序 sort(tiaodai+1,tiaodai+sum+1,cmp2); //暴力搜索结果 复杂度O(n²) 此处也可以再次优化 //虽然还是O(n²) 但n的基数相比最先少太多太多了 //所以总时间复杂度O(nlogn²)=O(2nlogn) 即O(nlogn) for(int i=1;i<=sum;i++) { for(int j=i+1;j<=sum;j++) { dis=min(dis,distance(tiaodai[i],tiaodai[j])); } } return dis; } int main() { int t;cin>>t; while(t--) { int n;cin>>n; for(int i=1;i<=n;i++) { cin>>p[i].x>>p[i].y; } sort(p+1,p+n+1,cmp1); printf("%.4lf\n",merge(1,n)); } return 0; }
SWUST OJ#794 最近对问题
最新推荐文章于 2023-12-20 16:54:27 发布