平面点对问题
输入:集合S中有n个点,n>1,
输出:所有的点对之间的最小距离.
通常算法:C(n,2)个点对计算距离,比较最小,需
O(n2)时间
分治策略:取S 的子集P,将P中的点划分成两个子
集PL和PR
MinDistance(P,X,Y)
输入:n个点的点集P,X是横坐标的排序数组,Y是纵坐标的
排序数组
输出:最近的两个点及距离。
1. 如果P中点数小于等于3,则直接计算其中的最小距离;
2. 排序X,Y;
3.做垂直线l将P划分为PL和PR,PL的点在l左边,PR的点
在l右边
4.MinDidtance(PL,XL,YL); δL = PL中的最小距离;
5.MinDistance(PR,XR,YR); δR = PR中的最小距离;
6.δ = min (δL,δR );
7.对于在垂直线两边距离δ范围内的每个点,检查是否有
点与它的距离小于δ,如果存在则将δ修改为新值.每个点至多比较6个点,n个点需要O(n)时间
分析:步1 O(1)
步2 O(nlogn)
步3 O(1)
步4-5 2T(n/2)
步6 O(1)
步7 O(n)
( ) (1) 3
) ( log )
2
( ) 2 (
= ≤
= +
T n O n
T n T n O n n
由递归树估计T(n) = O(nlog2n)
预排序的处理方法
在每次调用时将已经排好的数组分成两个排
序的子集,每次调用这个过程的时间为O(n)
( ) (1) 3
( ) 2 ( ) ( )
( ) ( ) ( log )
2
= ≤
= +
= +
T n O n
T n T O n
W n T n O n n
n
解得
T(n)=O(nlogn)
W(n) = O(nlogn)
算法的java实现代码
import java.io.IOException;
import java.math.*;
class Point{
int x;
int y;
};
public class NearestPoint {
static double INF = 1e20;
static double dist(Point a, Point b){
return Math.sqrt((float)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
static double nearest(Point[] points, int l, int r){
int n = r - l;
if(n==2)
{
double d1 = dist(points[l], points[l+1]);
double d2 = dist(points[l+1], points[r]);
double d3 = dist(points[l], points[r]);
if(d1 <= d2 && d1 <= d3)
{
return d1;
}
else if(d2 <= d3)
{
return d2;
}
else
{
return d3;
}
}
if(n==1)
{
double b = dist(points[l], points[r]);
return b;
}
if(n==0)
{
return INF;
}
int m=points[n/2+l].x;
double left=nearest(points, l, l+n/2);
double right=nearest(points, l+n/2, r);
double temp_nearest=left<right?left:right;
double ret=temp_nearest;
for(int i=n/2-1+l; i>=0 && points[i].x>m-temp_nearest; i--)
{
for(int j=n/2+l; j<=r && points[j].x<m+temp_nearest;j++)
{
double t=dist(points[i], points[j]);
if(t<ret)
{
ret=t;
}
}
}
return ret;
}
static void cmp(Point[] P, int n){
Point temp = new Point();
for(int i = 0; i < n; i++)
for(int j=i; j< n; j++)
{
if(P[i].x > P[j].x)
{
temp = P[i];
P[i] = P[j];
P[j] = temp;
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int num = 0;
try {
num = System.in.read()-48;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Point[] P = new Point[num];
for(int i = 0; i < num; i++)
{
P[i] = new Point();
P[i].x = (int)(Math.random()*25);
P[i].y = (int)(Math.random()*25);
}
System.out.println("随机生成的点的坐标如下:");
for(int i = 0; i< num; i++)
{
System.out.println("("+P[i].x+","+P[i].y+")");
}
double min = INF;
Point minP1 = new Point();
Point minP2 = new Point();
for(int i = 0; i < num; i++)
for(int j = i+1; j < num; j++)
{
double d = dist(P[i], P[j]);
if(d < min)
{
min = d;
minP1 = P[i];
minP2 = P[j];
}
}
System.out.println("用蛮力算法得到的最近距离为:"+min);
System.out.println("最近点坐标为:("+minP1.x+","+minP1.y+")和("+minP2.x+","+minP2.y+")");
cmp(P, num);
System.out.println("按照横坐标排序后,各点坐标如下:");
for(int i = 0; i< num; i++)
{
System.out.println("("+P[i].x+","+P[i].y+")");
}
min = nearest(P, 0, num-1);
System.out.println("用分治算法得到的最近距离为:"+min);
}
}