算法分析与设计的一次实验题,因为输出需要输出最接近的点对,所以这里卡住了好久,这里挂一下代码记录一手。
【问题描述】给定二维平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。使用递归与分治策略求解二维平面上的最接近点对问题。假设所有点的集合为S,m为S中所有点的x坐标的中位数,垂直线x=m将集合S均匀分割为左右两个子集合S1和S2。
【输入形式】在屏幕上输入点的个数,以及所有点的x和y坐标。
【输出形式】第一次分割时,将所有点集合S分割为左右两个子集合S1和S2,分别输出左右子集合S1和S2,以及所有点集合S的最接近点对的距离以及最接近点对。
【样例输入】
10
-15.4 -57.3
13.2 30.1
-87.5 93.2
47.6 -12.7
94.7 61.5
56.8 -57.1
27.8 43.5
-28.1 19.0
-96.2 47.5
55.5 -93.3
【样例输出】
42.8
-28.1 19.0
13.2 30.1
36.2
55.5 -93.3
56.8 -57.1
19.8
13.2 30.1
27.8 43.5
【样例说明】
输入:10个点,后续每行为每一点的x和y坐标。
输出:左右子集合S1和S2,以及所有点集合S的最接近点对的距离以及最接近点对。例如,前面三行中,S1的最接近点对的距离为42.8,最接近点对的x和y坐标分别为(-28.1,19.0)和(13.2,30.1)。输出最接近点对坐标时,先输出的点的x坐标小于后输出点的x坐标。中间三行和最后三行分别为子集合S2和集合S的最接近点对的距离以及最接近点对。
如下图所示,子集合S1点以蓝色表示,子集合S2以绿色表示。蓝色连线为子集合S1最接近点对间的线段;绿色连线为子集合S2最接近点对间的线段;紫色连线为集合S最接近点对间的线段。
下面就是代码了,有点乱,见谅。
#include<iostream>
#include<vector>
#include<algorithm>
#include<iomanip>
#define inf 20000 //这个指那个最大的无穷值,我认为20000够用了,再大的数据建议直接设无穷
using namespace std;
int n;
double minj;
struct point
{
double x;
double y;
};
point vec[1000];
point jilu[2];
bool sortBy_x(point point1, point point2) //根据x坐标从小到大排序
{
if (point1.x == point2.x)
return point1.y < point2.y;
return point1.x < point2.x;
}
bool sortBy_y(point point1, point point2) //根据纵坐标从小到大排序
{
return point1.y < point2.y;
}
double getDistance(point &point1, point &point2)
{
double dis_x = point1.x - point2.x;
double dis_y = point1.y - point2.y;
return sqrt(dis_x*dis_x+dis_y*dis_y);
}
double getMin(int low, int high)
{
/*if(low==0&&high==(n-1)/2)flag=2;
if(low==((n-1)/2+1)&&high==n-1)flag=3;
if(low==0&&high==n-1)flag=4;*/
if (high - low == 1) //2个结点
{
if(getDistance(vec[low], vec[low + 1])<minj)
{
jilu[0]=vec[low];
jilu[1]=vec[low+1];
minj=getDistance(vec[low],vec[low+1]);
}
return getDistance(vec[low],vec[low + 1]);
}
else if (high - low == 2) //3个结点
{
double dist1= getDistance(vec[low], vec[low + 1]);
double dist2 = getDistance(vec[low], vec[low + 2]);
double dist3 = getDistance(vec[low+1], vec[low + 2]);
if(dist1<=dist2&&dist1<=dist3&&dist1<minj)
{
jilu[0]=vec[low];
jilu[1]=vec[low+1];
minj=getDistance(vec[low],vec[low+1]);
}
if(dist2<=dist1&&dist2<=dist3&&dist2<minj)
{
jilu[0]=vec[low];
jilu[1]=vec[low+2];
minj=getDistance(vec[low],vec[low+2]);
}
if(dist3<=dist2&&dist3<=dist1&&dist3<minj)
{
jilu[0]=vec[low+1];
jilu[1]=vec[low+2];
minj=getDistance(vec[low+1],vec[low+2]);
}
return min(min(dist1, dist2), dist3);
}
else
{
int mid = (low + high) / 2;
double left_min = getMin(low, mid);
double right_min = getMin(mid + 1, high);
double d = min(left_min,right_min);
point res[1000];
int i,j;
int ans=0;
for (i = low; i <= high; i++) //遍历一遍数组,得到与横坐标与 中点横坐标距离在d以内的点
{
if (fabs(vec[i].x - vec[mid].x) < d)
res[++ans]=vec[i];
}
sort(res+1,res+ans+1,sortBy_y); //根据纵坐标从小到大排序
for (i = 1; i <ans; i++)
{
for (j = i + 1; j <ans+1; j++)
{
if (res[j].y - res[i].y >= d)
break;
double dp = getDistance(res[i], res[j]);
if (dp < d)
{
d = dp;
}
if(dp<minj)
{
jilu[0]=res[i];
jilu[1]=res[j];
minj=dp;
}
}
}
return d;
}
}
int main()
{
cin >> n; //输入点的个数
for (int i = 0; i < n; i++)
{
cin >> vec[i].x >> vec[i].y;
}
sort(vec,vec+n, sortBy_x);
minj=inf;
cout<<fixed<<setprecision(1)<<getMin(0, (n-1)/2)<<endl;
if(jilu[0].x>jilu[1].x)
{
point t1;
t1=jilu[0];
jilu[0]=jilu[1];
jilu[1]=t1;
}
cout<<jilu[0].x<<" "<<jilu[0].y<<endl;
cout<<jilu[1].x<<" "<<jilu[1].y<<endl;
jilu[0].x=0;
jilu[0].y=0;
jilu[1].x=0;
jilu[1].y=0;
minj=inf;
cout<<fixed<<setprecision(1)<< getMin(((n-1)/2+1), (n-1))<<endl;
if(jilu[0].x>jilu[1].x)
{
point t2;
t2=jilu[0];
jilu[0]=jilu[1];
jilu[1]=t2;
}
cout<<jilu[0].x<<" "<<jilu[0].y<<endl;
cout<<jilu[1].x<<" "<<jilu[1].y<<endl;
jilu[0].x=0;
jilu[0].y=0;
jilu[1].x=0;
jilu[1].y=0;
minj=inf;
cout<<fixed<<setprecision(1)<< getMin(0, n-1) << endl;
if(jilu[0].x>jilu[1].x)
{
point t3;
t3=jilu[0];
jilu[0]=jilu[1];
jilu[1]=t3;
}
cout<<jilu[0].x<<" "<<jilu[0].y<<endl;
cout<<jilu[1].x<<" "<<jilu[1].y<<endl;
return 0;
}