从平面上最近的点对,谈谈分治算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tham_/article/details/77838718

首先介绍一下分治(Divide-and-Conquer )算法:


设计过程分为三个阶段

–Divide: 整个问题划分为多个子问题
–Conquer:求解各子问题(递归调用正设计的算法)
–Combine:合并子问题的解, 形成原始问题的解

如下图:

举例说明



题目大意

给你n个点,求出其中点与点之间的最短距离。


 算法设计

这个题目就是用上面的分治算法。将所有的点分为两部分,左边和右边,那么最短距离要么在左边,要么在右边,要么跨边界。

那么我们就可以递归了,如果只剩一个点,就返回一个超过10000的值,如果只有两个点,直接求距离。

那如果n个点,就分两部分,先递归求出左边最小值,右边最小值,然后求出二者的最小值min,然后枚举跨边界的的点的距离,这个时候我们只需要取两边距离小于min的就行,因为大于min的对我们的结果没有意义。

 

在这里我做了一下优化,就是代码中那个循环为何小于i+7,而不是cnt,其实cnt也行,只是浪费时间。实际上,我们找出距离边界的所有点,直接枚举两两之间的距离就行,和min作比较,返回最小值。


如何优化,证明如下:


1、情况描述

2、找点

3、方法

4、最多6个这样的点

5、鸽巢原理

 

 

 

 

code:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct POINT 
{
	double x,y;
}point[10010],temp[10010];

double dis(struct POINT p1, struct POINT p2)
{
	return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

int cmp(const void * a, const void * b)
{
	struct POINT * c = (struct POINT *)a;
	struct POINT * d = (struct POINT *)b;
	if (c->x != d->x)
	{
		return c->x > d->x;
	}
	else
		return c->y > d->y;
}
int cmp1(const void * a, const void * b)
{
	struct POINT * c = (struct  POINT *)a;
	struct POINT * d = (struct  POINT *)b;
	if (c->y != d->y)
	{
		return c->y > d->y;
	}
	else
		return c->x > d->x;
}

double findMin(int l, int r)
{
	if (l == r)
	{
		return 10010;
	}
	if (l == r - 1)
	{
		return dis(point[l], point[r]);
	}
	double tmp1 = findMin(l,(l + r) >> 1);
	double tmp2 = findMin(((l + r) >> 1) + 1, r);
	double Mindis,tmp, mid;
	mid = point[(l + r) >> 1].x;
	/*mid = (point[l].x + point[r].x) / 2.0;*/
	int i,j,cnt = 0;
	if (tmp1 < tmp2)
	{
		Mindis = tmp1;
	}
	else
		Mindis = tmp2;
	for (i = l; i <= r; ++ i)
	{
		if (fabs(point[i].x - mid) < Mindis)
		{
			temp[cnt ++] = point[i];
		}
	}
	qsort(temp, cnt, sizeof(temp[0]), cmp1);
	for (i = 0; i < cnt - 1; ++ i)
	{
		/*for (j = i + 1; j < cnt; ++ j)*/
		for (j = i + 1; j < i + 7 && j < cnt; ++ j)
		{
			tmp = dis(temp[i], temp[j]);
			if (tmp < Mindis)
			{
				Mindis = tmp;
			}
		}
	}
	return Mindis;

}
int main()
{
	int n,i,j;
	double minDis;
	while (scanf("%d", &n)==1 && n)
	{
		for (i = 0; i < n; ++ i)
		{
			scanf("%lf%lf", &point[i].x, &point[i].y);
		}
		qsort(point, n, sizeof(point[0]), cmp);
		minDis = findMin(0, n-1);
		if (minDis > 10000)
		{
			printf("INFINITY\n");
		}
		else
			printf("%.4lf\n", minDis);
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/tham_/article/details/77838718