您的位置:首页 > 其它

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

2017-09-04 16:20 197 查看

首先介绍一下分治(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: