求n个点最短距离(分治思想)

转载自:https://blog.csdn.net/wangyangkobe/article/details/6436327感谢大佬的代码保存记录一下 

#include <iostream>
#include <ctime>
#include <iterator>
#include <functional>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
struct Point
{
	int x;
	int y;
	Point(){}
	Point(int m_x, int m_y)
		:x(m_x), y(m_y){}
};
/************************************************************************/
/* 函数功能:按点的X坐标排序                                            */
/************************************************************************/
struct CmpX : public binary_function<bool, Point, Point>
{
	bool operator() (const Point& lhs, const Point& rhs)
	{
		return (lhs.x < rhs.x);
	}
};
/************************************************************************/
/* 函数功能:按点的Y坐标排序                                            */
/************************************************************************/
struct CmpY : public binary_function<bool, Point, Point>
{
	bool operator() (const Point& lhs, const Point& rhs)
	{
		return (lhs.y < rhs.y);
	}
};
/************************************************************************/
/*  类功能:产生无重复的随机数	
	类成员:num    表示要产生的随机数的个数
			bound  表示每个随机数的范围[0, bound-1).                    */
/************************************************************************/
class Random
{
public:
	explicit Random(int m_num, int m_bound)
		:num(m_num), bound(m_bound)
	{
		arr = new int[m_bound];
		for(int i = 0; i < bound; i++)
			arr[i] = i;
	}
	int* GetResult()
	{
		int temp = 0;
		srand((unsigned)time(0));
		for (int i = 0; i < num; i++)
		{
			temp = rand() % (bound - i - 1) + i;
			swap(arr[i], arr[temp]);
		}
		return arr;
	}
	~Random()
	{
		delete []arr;
	}
private:
	int *arr;
	int num;	//随机数的个数
	int bound;  //随机数的范围
};
/************************************************************************/
/* 函数功能:求两点间的距离                                             */
/************************************************************************/
inline double Distance(const Point& lhs, const Point& rhs)
{
	int x_diff = lhs.x - rhs.x;
	int y_diff = lhs.y - rhs.y;
	double res = x_diff * x_diff + y_diff *y_diff;
	return sqrt(res);
}
/************************************************************************/
/* 函数功能:求数组中两点间的最短距离                                   */
/************************************************************************/
double GetShortestDistace(Point arr[], int low, int high)
{
	double result = 0.;
	
	if (high - low < 3) //小于等于3个点时
	{
		if (high - low == 1) //2个点时
		{
			double distance = Distance(arr[low], arr[high]);
			return distance;
		}
		else //3个点
		{
			double distance1 = Distance(arr[low], arr[low + 1]);
			double distance2 = Distance(arr[low], arr[low + 2]);
			double distance3 = Distance(arr[low + 1], arr[low + 2]);
			return min(min(distance1, distance2), distance3);
		}
	}
	int middle = (low + high) / 2;
	double left_distance = GetShortestDistace(arr, low, middle);		//求middle左边的最短距离
	double right_distance = GetShortestDistace(arr, middle + 1, high);	//求middle右边的最短距离
	
	double delta = min(left_distance, right_distance); //中间区域的界限
	result = delta;
	vector<Point> midArea;	//存放中间条带区域的点
	for (int k = low; k < high; k++)
	{
		if(arr[k].x > arr[middle].x - delta && arr[k].x < arr[middle].x + delta)
			midArea.push_back(arr[k]);
	}
	sort(midArea.begin(), midArea.end(), CmpY()); //按Y坐标排序
	int size = midArea.size();
	for (int i = 0; i < size; i++)
	{
		int k = (i + 7) > size ? size : (i+7);	//只有选取出7个点(证明过程没看懂)
		for (int j = i+1; j < k; j++)
		{
			if(Distance(midArea.at(i), midArea.at(j)) < result)
				result = Distance(midArea.at(i), midArea.at(j));
		}
	}
	return result;
}

#define N 100 //点的个数
int main()
{
	Point arr[N];
	Random random(2*N, 1000);
	int *result = random.GetResult();
	for (int i =0; i < N; i++)
		arr[i] = Point(result[i], result[i + N]);
	sort(arr, arr + N, CmpX());
	double res = GetShortestDistace(arr, 0, N);
	cout<<"The shortest distance is:"<<res<<endl;
}

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个用Java实现平面短距离的两个点的代码,同时也体现了分治思想: ``` import java.util.*; public class ClosestPair { static class Point { double x, y; public Point(double x, double y) { this.x = x; this.y = y; } } static class Pair { Point p1, p2; double distance; public Pair(Point p1, Point p2, double distance) { this.p1 = p1; this.p2 = p2; this.distance = distance; } } public static Pair closestPair(Point[] points) { Arrays.sort(points, (p1, p2) -> Double.compare(p1.x, p2.x)); return closestPair(points, 0, points.length - 1); } private static Pair closestPair(Point[] points, int left, int right) { if (left >= right) { return null; } int mid = (left + right) / 2; Pair leftPair = closestPair(points, left, mid); Pair rightPair = closestPair(points, mid + 1, right); Pair minPair = min(leftPair, rightPair); List<Point> strip = new ArrayList<>(); double midX = points[mid].x; for (int i = left; i <= right; i++) { if (Math.abs(points[i].x - midX) < minPair.distance) { strip.add(points[i]); } } strip.sort((p1, p2) -> Double.compare(p1.y, p2.y)); for (int i = 0; i < strip.size(); i++) { for (int j = i + 1; j < strip.size() && strip.get(j).y - strip.get(i).y < minPair.distance; j++) { Pair pair = new Pair(strip.get(i), strip.get(j), distance(strip.get(i), strip.get(j))); if (pair.distance < minPair.distance) { minPair = pair; } } } return minPair; } private static Pair min(Pair p1, Pair p2) { if (p1 == null) { return p2; } if (p2 == null) { return p1; } return p1.distance < p2.distance ? p1 : p2; } private static double distance(Point p1, Point p2) { double dx = p1.x - p2.x; double dy = p1.y - p2.y; return Math.sqrt(dx * dx + dy * dy); } public static void main(String[] args) { Point[] points = new Point[] { new Point(0, 0), new Point(1, 1), new Point(2, 2), new Point(3, 3) }; Pair pair = closestPair(points); System.out.println(pair.distance); } } ``` 这个算法的思想是:先按照x坐标排序,然后递归地将集分成左右两部分,分别出左右两部分的最近对,然后取两部分中最近的对作为当前区间的最近对。接着,我们需要考虑两个点分别在左右两部分的情况,这时我们需要将集按照y坐标排序,然后在中间的一段区间内暴力枚举所有对,找到距离最近的对。最后,我们将三种情况中距离最近的对作为整个点集的最近对。 希望这个代码能够帮到你!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值