问题描述:设p1=(x1,y1),p2=(x2,y2),...,pn=(xn,yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对(二维平面)。
1、蛮力法:直接用欧几里得距离计算即可
#include
#include
#include
using namespace std;
struct In{
double x;
double y;
}p[500];
int main(){
int n;
double min,d;
double x1,y1,x2,y2;
printf("输入n:\n");
scanf("%d",&n);
printf("输入%d个点:\n",n);
for(int i=0;id){
min=d;
x1=p[i].x;y1=p[i].y;
x2=p[j].x;y2=p[j].y;
}
}
printf("输出最近对的距离:\n%lf\n",sqrt(min));
printf("输出最近对的两个点:\n(%lf,%lf)与(%lf,%lf)\n",x1,y1,x2,y2);
}
/*
5
85.1 52.1 65 85.6 12.6 5.2 2.1 6.1 3 9.64
*/
2、分治法
算法效率取决于划分点m的选取,要遵循平衡子问题的原则;
思想:点(x,y)
首先对所有点s按照x坐标升序排列,选取m为x的中位数;
Closepoints(s):
若只有一个点,return inf;
若只剩两个点,return 欧几里得距离;
若剩下三个点,分别计算两两点距离,比较三个中的最小值,将其返回;
构造集合s1,s2;使得s1为x坐标小于m,s2为x坐标大于m;
递归:d1=ClosePoints(s1);d2=ClosePoints(s2);
d=min(d1,d2);
构造集合p1,p2;p1为m减s1中点的x坐标的差值不超过d,p2为s2中点的x坐标减m的差值不超过d;
对p1,p2按照y坐标升序排列;
对于p1中每一个点,找出其y坐标与p2中点的y坐标差值不超过d的点,计算两点距离为dp;
return min(d,dp);
注意:p1 p2点因 鸽舍原理 点不会超过6个(有说8个的)
#include
#include
#include
#include
#include
using namespace std;
/*递归中慎用全局变量(若这些变量涉及到递归传参)*/
struct In{
double x;
double y;
};
int cmp(const void *a,const void *b){
return (*(In*)a).x - (*(In*)b).x;
}
int cmp1(const void*a,const void*b){
return (*(In*)a).y>(*(In*)b).y?1:-1;
}
double ClosePoint(In s[],int n,In f[]){
int i,j=0,k=0,t,flag,nk;
double d1,d2,d,di,dt,m;
struct In p1[100],p2[100],s1[300],s2[300];
struct In t1[2],t2[2];
if(n==1)return 20000;//inf无限大 一个点
if(n==2){//两个点
f[0]=s[0];f[1]=s[1];
d=pow(s[0].x-s[1].x,2)+pow(s[0].y-s[1].y,2);
return d;
}
if(n==3){//三个点
d=pow(s[0].x-s[1].x,2)+pow(s[0].y-s[1].y,2);
d1=pow(s[0].x-s[2].x,2)+pow(s[0].y-s[2].y,2);
d2=pow(s[2].x-s[1].x,2)+pow(s[2].y-s[1].y,2);
if((dm)s2[t++]=s[i];
d1=ClosePoint(s1,flag,f);
t1[0]=f[0];t1[1]=f[1];//记录最短距离的位置
d2=ClosePoint(s2,t,f);
t2[0]=f[0];t2[1]=f[1];
if(d1