最近对问题

最近对问题EfficientClosetPair(P,Q)

1.问题

令P为笛卡几平面上n>1个点构成的集合,假设每个点都不一样,给定每个点的坐标,找出最近两个点的距离。

2.解析

输入:输入n>=2个点的坐标,按x轴坐标升序排序,得到数组P;按Y轴坐标升序排序,得到数组Q
输出:最近点对之间俺的欧几里得距离
if n<=3:

  • 蛮力算法:
    枚举两个点对,得到最小距离的点对,时间复杂度为O(N^2)

else:

  • 分治求解法

    • divide:
      将n个元素从中间n/2分开,分为[left,n/2]和[n/2+1,right]
    • merge:
      将P中的前[n/2]个点复制到Pl
      将Q中的前[n/2]个点复制到Ql
      将P中的后[n/2]个点复制到Pr
      将Q中的后[n/2]个点复制到Qr
      dl=EfficientClosestPair(Pl,Ql)
      dr=EfficientClosestPair(Pr,Qr)
      d=min{dl,dr}
      通过递归分解求治dl,dr得到最短距离
      还有一种情况:距离最近的两个点分别位于分界线的两侧。
      设S是来自Q,位于分割线2d宽度范围内的垂直带的点的列表(其他点对的距离都至少为d),因Q的特点,S是按纵坐标升序排列的。扫描S,当遇到小于d(min)时,更新。
      在这里插入图片描述
      m=P[n/2-1].x
      将Q中所有[x-m]<d的点复制到数组S[0,num-1]
      dminsq=d^2
      for i=0 to num-2 do
      k=i+1
      while k<=num-1&&(S[k].y-S[i].y)^2<dminsq
      dminsq=min((S[k].x-S[i].x)^2+
      (S[k].y-S[i].y)^2,dminsq)
      k=k+1
      retuen sqrt(dminsq)

3.设计

在这里插入代码片```
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h> 

typedef struct point {
	double x;
	double y;
} point;

int cx(const void *_a, const void *_b) {
	point *a = (point*)_a;
	point *b = (point*)_b;
	return a->x - b->x;
} 

int cy(const void *_a, const void *_b) {
	point *a = (point*)_a;
	point *b = (point*)_b;
	return a->y - b->y;
}


double distant(point i, point j) {
	return sqrt(pow(i.x - j.x, 2) + pow(j.y - i.y, 2));
}

double piar(point *points, int start, int end) {
	double d = INT_MAX;
	if (start == end) {
		return d;	
	}
	if (start + 1 == end) {
		return distant(points[start], points[end]);
	}
	int mid = (start + end) / 2;
	double d1 = piar(points, start, mid);
	double d2 = piar(points, mid + 1, end);
	d = fmin(d1, d2);
	point temp[end - start + 1];
	int top = 0;
	for (int i = start; i <= end; ++i) {
		if (abs(points[i].x - points[mid].x) < d) {
			temp[top++] = points[i];
		} 
	}
	qsort(temp, top, sizeof(point), cy);
	for (int i = 0; i < top - 1; ++i) {
		for (int j = i + 1; j < top; ++j) {
			if (abs(points[i].y - points[j].y) < d) {
				double d3 = distant(points[i], points[j]);
				if (d3 < d) {
					d = d3;
				}
			}
		}
	}
	return d;
}

int main() {
	int n;
	printf("请输入点的数量:");
	scanf("%d", &n);
	point points[n];
	for (int i = 0; i < n; ++i) {
		printf("请输入x和y坐标: ");
		scanf("%lf%lf", &points[i].x,&points[i].y); 
	}
	qsort(points, n, sizeof(point), cx);
	printf("最小的距离为: %.2f", piar(points, 0, n - 1));
	return 0; 
}
/*
 5
 0 0
 0 1
 0 3
 9 1
 9 8

*/

4.分析

  • 合并的复杂度O(n),分治递归的复杂度O(n/2)
  • 总时间复杂度O(nlogn)

5.源码

最近对问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值