作业5——分治算法之最近对问题

博客探讨了如何使用分治策略解决最近对问题。在笛卡尔平面上,通过对点集进行排序并沿中位线划分,递归地解决大小减半的子问题。在合并子解时,通过考虑特定宽度的垂直带来找到可能的最近对,算法的时间复杂度为O(nlogn)。
摘要由CSDN通过智能技术生成

1,问题

最近对问题

2,解析

令P为笛卡尔平面上n>1个点构成的集合。简单起见,假设集合中每个点都不一样。我们还假设这些点是按照其x周坐标升序排列的。为了更加方便,我们还按照点的y轴坐标在另一个列表中进行升序排列,分别记为Px,Py。当2<=n<=3时,通过蛮力求解出D。当n>3时,可以利用点集在方向上的中位数mid,在该处作一条垂线,将点集分成大小分别为ceil(n/2) 和int(n/2)两个子集Px1和Px然后通过递归求解。但是,这样的D不一定是整个P中的最近对距离,因为距离最近的两个点可别位于中线mid的两侧。因此,在合并较小子问题的解时,需要检查是否存在这样的点。显然,我们可以在关注以分割带为对称的,宽度为2D的垂直带中的点,因为任何其它点对的距离都至少为D。是来自Py,位于分割线2D宽度范围内的垂直带的点的列表。由于Py的特点,因为S是按照y轴升序的。我们扫描该列表,当遇到更近的点对时,更新目前为止的D。初始情况下,Dmin=D,但接下来Dmin<D。设p(x,y)为列表中的点。如果另一个点p’(x’,y’)和p点的距离小于Dmin,那么p’一定在p的列表后面,并且两点在y轴上的距离一定小于Dmin。在几何上,这意味着p’点一定包含在以mid线为对称轴,长为2D,宽为D的矩形中。该算法主要原理利用了以下事实:矩形内一般只能包含少量候选点,因为每一边内,点与点的距离至少为D.其实很容易证明,在矩形内满足条件的点(包括p在内)的总数不超过8个,更细致的研究表明这个数不会大于6。也就是说,在移动下一个点之前,算法最多只需要考虑S中的下5个点。

3,设计

int EfficientClosestPair(Px,Py,pointnum,Dmin){
if n < 3 return 蛮力算法;
else {
将Px的前ceil(n/2)个点复制到Px1
后n/2个点复制到Px2
将Py的前ceil(n/2)个点复制到Py1
后n/2个点复制到Py2

 Dmin1 = EfficientClosestPair(Px1,Py1);
 Dmin2 = EfficientClosestPair(Px2,Py2);
 Dmin = min(Dmin1,Dmin2);

  S = Py中|x - mid|<Dmin 的点集
  for (i from 0 to n){
     for (j from i+1 to i+6){
           更新Dmin
} 

}
}

4,分析

无论将问题划分为两个规模减半的子问题,还是合并子问题的解,该算法都只需要线性时间。因此,假设n是2的幂,我们得到算法运行时间的递归式:
T(n) = 2T(n/2) + f(n)
其中f(n) ∈O(n).应用主定理,T(n) = O(nlogn).

5,源码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
struct point {
	int x = NULL;
	int y = NULL;
};

void swap(int x, int y) {
	int tmp;
	tmp = x;
	x = y;
	y = tmp;
}

int direct(point P[], int n) {
	int Dmin = 1000;
	for (int i = 0; i < n - 1; i++) {
		for (int j = i + 1; j < n; j++) {
			int dist = (P[i].x - P[j].x) * (P[i].x - P[j].x) + (P[i].y - P[j].y) * (P[i].y - P[j].y);
			if (Dmin > dist) Dmin = dist;
		}
	}
	return Dmin;
}

int  EfficientClosestPair(point Px[],point Py[], int n,int Dmin){
	int mid = (n - 1) / 2 + 1;

	if (n <= 3)//如果pointnum小于等于3,蛮力求解
	{
		 Dmin = direct(Px, n);
		 return Dmin;
	}

	else 
	{
		point Px1[(10 - 1) / 2 + 1];
		point Py1[(10 - 1) / 2 + 1];
		point Px2[10 / 2];
		point Py2[10 / 2];
		for (int i = 0; i < mid; i++) {
			Px1[i].x = Px[i].x;
			Px1[i].y = Px[i].y;
			Px2[i].x = Px[i + 1].x;
			Px2[i].y = Px[i + 1].y;

			Py1[i].x = Py[i].x;
			Py1[i].y = Py[i].y;
			Py2[i].x = Py[i + 1].x;
			Py2[i].y = Py[i + 1].y;
		}
		int Dmin1 = EfficientClosestPair(Px1, Py1,mid,Dmin);
		int Dmin2 = EfficientClosestPair(Px2, Py2,n/2,Dmin);
		Dmin = Dmin1 < Dmin2 ? Dmin1 : Dmin2;

		point S[10];
		int k = 0;
		for (int i = 0; i < n; i++) {
			if (Py[i].x >= mid - Dmin && Py[i].x <= mid + Dmin) {
				S[k].x = Py[i].x;
				S[k].y = Py[i].y;
				k++;
			}
		}

		for (int i = 0; i < n; i++) {
			for (int j = i + 1; j < i + 6; j++) {
				int dist = (S[i].x - S[j].x) * (S[i].x - S[j].x) + (S[i].y - S[j].y) * (S[i].y - S[j].y);
				if (Dmin > dist) Dmin = dist;
			}
		}

		return Dmin;

	}
}


int main() {
	int n = 10;
	point P[10];
	int Dmin = 1000;
	for (int i = 0; i < n; i++) {
		scanf_s("%d%d", &P[i].x, &P[i].y);
	}
	point Px[10], Py[10];
	for (int i = 0; i < n; i++) { //Px按照x轴从小到大排序
		for (int j = 0; j < n - i - 1; j++) {
			if (Px[j].x > Px[j + 1].x) {
				swap(Px[j].x, Px[j + 1].x);
				swap(Px[j].y, Px[j + 1].y);
			}
		}
	}

	for (int i = 0; i < n; i++) { //Py按照y轴从小到大排序
		for (int j = 0; j < n - i - 1; j++) {
			if (Py[j].y > Py[j + 1].y) {
				swap(Py[j].x, Py[j + 1].x);
				swap(Py[j].y, Py[j + 1].y);
			}
		}
	}

	printf("%d",EfficientClosestPair(Px, Py, n,Dmin));

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值