c语言 最近点对问题(分治法+递归)

这个问题我从理解到证明到代码实现,花了差不多两天的时间,还不乏寻求帮助,我也是醉了…

Problem Description(题目摘自杭电
Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded.
In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring.
简要地说就是:给定平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小

Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.

Input
The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates of a toy. The input is terminated by N = 0.

Output
For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places.

Sample Input
2
(0 , 0)
(1 , 1)
2
(1 , 1)
(1 , 1)
3
(-1.5 , 0)
(0 , 0)
(0 , 1.5)
0
Sample Output
0.71
0.00
0.75

思路求解:

1. 简单的一维的情况。
就是在一条直线上,寻找最近点对的距离,这个我们其实可以进行直接的循环比较,简单说来就是先拿一个点,让它与其他(n-1)个点计算距离,每次比较存储最小即可。但这样效率太低了,时间复杂度分分钟都到O(n^2)上去了。因此,可以采用分治的方法,将n个点分为n/2个左边集合S1和n/2右边集合S2点集,然后在每个子递归集合中求最小值点,即可。当然,如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决,但如果这2个点分别在S1和S2中,问题就不那么简单了.
c语言 最近点对问题(分治法+递归)_第1张图片
递归的在S1和S2上找出其最接近点对{A,B}和{D,E},并设d=min{|A-B|,|D-E|},因此最接近点对就是{A,B}或者{D,E},或者存在|C-D| 2. 二维的情况
首先,与一维的区别就是多了y轴,其实,理解起来差不多。我们利用类似的一维的方法将这些点按照x轴坐标从小到大的顺序进行排序,就会得到类似的景象,先不管y轴,此时,同理在(m-d,m]和[m,m+d)中就可以找到符合要求的最小值点对,这应该很容易理解的。然后,在考虑y轴,当然时间复杂度二分法递归本身的复杂度为O(logn),那么下面进行的应该如何控制时间复杂度,使之不那么大呢?我们在(m-d,m+d)的区域中,以(m-d,m)中·的任意一点为A,那么存在所对应的距离小于等于d的另外一点所在的区域一定是在以A为圆心,半径为d的圆周上。为了便于证明所存在点的个数是有限的常数个数,可以画一个长为2d,宽为d的矩形,那么由鸽巢原理可得,最多只有六个点存在使得距离最小,因此复杂度就是常数O(n),因此总的时间复杂度就是O(nlogn).
c语言 最近点对问题(分治法+递归)_第2张图片

#include
#include
#include
#include

#define INF 2147483647
#define N 10000
struct node {
	double x;
	double y;
}point[N];

int cmp(const void* a, const void* b)//结构体的快排调用 
{
	struct node ac = *(struct node*)a;
	struct node bd = *(struct node*)b;
	if (ac.x != bd.x)
		return ac.x - bd.x;//按照x从小到大的顺序排序
	else return ac.y - bd.y;//当x相等的时候,按照y的从大到小的顺序排序 
}

int cmpy(const void* a, const void* b)//一维数组的快排调用 
{
	return (*(int*)a - *(int*)b);
}

double mindistance(double left, double right)//返回大小关系 
{
	return left < right ? left : right;
}

double distance(int left, int right)//计算两点的距离的函数 
{
	return sqrt((point[left].x - point[right].x) * (point[left].x - point[right].x) + ((point[left].y - point[right].y) * (point[left].y - point[right].y)));
}

double Closest_Pair(int left, int right)
{
	double End_dis = INF;//距离差的初始值,无穷大 
	int i = 0, j = 0, k = 0;//循环变量 

	if (left == right)//只有一个点的时候,返回无穷大 
		return End_dis;

	if (right - left == 1)// 刚好两个点的时候,返回两点的距离即可 
		return distance(left, right);

	int mid = (left + right) / 2;//大于等于三个点的时候

	double distanceleft = Closest_Pair(left, mid);//左边递归
	double distanceright = Closest_Pair(mid + 1, right);//右边递归

	End_dis = mindistance(distanceleft, distanceright);//比较左右两边的点对距离,找出最小值

	int temp[N] = { 0 };//储存宽度为d的点 

	for (i = left; i <= right; i++)//找出符合要求的距离mid横坐标小于等于d的点 
	{
		if (fabs(point[mid].x - point[i].x) <= End_dis)
			temp[k++] = i;//temp用于暂时储存符合要求的点的序号 
	}
	for (i = 0; i <= k - 1; i++)//纵坐标寻找最短距离 
		for (j = i + 1; j <= k - 1; j++)
			if (point[temp[j]].y - point[temp[i]].y < End_dis)
				End_dis = mindistance(End_dis, distance(temp[i], temp[j]));
	return End_dis;
}

int main()
{
	int n = 1;
	while (scanf_s("%d", &n) == 1 && n)//可以多次赋值,直到为“零”输入 
	{
		for (int i = 0; i < n; i++)
			scanf_s("%lf %lf", &point[i].x, &point[i].y);
		qsort(point, n, sizeof(point[0]), cmp);
		printf("%.2lf\n", Closest_Pair(0, n - 1) / 2);
	}
	return 0;
}

你可能感兴趣的:(递归认识,#,算法题)