代码改变世界

实用算法实现-第 29 篇 计算几何学

2012-02-07 19:39  myjava2  阅读(228)  评论(0编辑  收藏  举报

29.1    最近点对

“最近”是指通常意义上的欧几里德距离。《算法导论》中对这个问题进行了介绍。[i]问对于经典的分治法求最近点对有深入的介绍和详尽的伪代码。

29.1.1   实例

PKU JudgeOnline, 3714, Raid.

29.1.2   问题描述

给定n个岗位和n个战士的坐标(0 ≤ X ≤1000000000, 0 ≤ Y ≤ 1000000000)。问这些战士当中,离某个岗位最近的距离是多少?

29.1.3   输入

2

4

00

01

10

11

22

23

32

33

4

00

00

00

00

00

00

00

0 0

29.1.4   输出

1.414

0.000

29.1.5   分析

这也是一个最近距离的问题,只不过是两个集合中的元素的最近距离的问题。采用的方法不同于经典的最近距离点对的分治算法,但是思想上也有类似的地方。

对于每个战士(x0, y0),首先找到一个点,这个点是x最接近x0的所有点中y最接近y0的点,求出(x, y)、(x0, y0)两点距离dis。若minDis > dis,令minDis = dis。在[x - minDis, x + minDis]的横坐标范围内移动x,并对每个x,寻找y最接近y0的点(x, y),若minDis > dis,令minDis = dis。

上述描述中,“最接近x0的x”或者“最接近y0的y”都通过对有序数组的二分查找法来找出。

29.1.6   程序

29.2    线段相交

关于线段相交,《算法艺术与信息学竞赛》介绍得比较细致。

29.2.1   实例

PKU JudgeOnline, 1039, Pipe.

29.2.2   问题描述

如上图所示,有一条管子,拐角处的两点坐标为(x, y)和(x, y + 1)。有一束光从入口射入,遇到管壁则被阻挡。求光所能达到的最大的x。

29.2.3   输入

4

01

22

41

64

6

01

2-0.6

5-4.45

7-5.57

12-10.8

17-16.55

0

29.2.4   输出

4.67

Through all the pipe.

29.2.5   分析

《算法艺术与信息学竞赛》对这个题有结题报告。
29.2.6   程序


29.3    Melkman在线凸包算法

《算法艺术与信息学竞赛》比较全面、生动地介绍了凸包算法及其应用。

Melkman凸包算法继承Graham-Scan算法的主要思想,并更近一步地采用双端队列,动态地在队列两头进行增删操作,维护“凸性”。

一个Melkman凸包算法的实例如下:

[ii]中描述的Melkman凸包算法如下所示:

1.  t ← 1; b ← 0;//这里似乎Melkman弄反了,应该改成:t ← 0;b ←1;

vl← input; v2 ← input; v3 ← input;

if (Vl, v2, v3) > 0

then begin push vl; push v2; end;

else begin push v2; push v1; end;

pushv3 ; insert v3;

2.   v ← input;

until (v, db, db+l) < 0 or (dt-1, dt, v) < 0

do v ← inputend;

3.   until (dt-l,dt, v) > 0 do pop dt end;

pushv;

4.  until(v, db, db+l) > 0 do remove db end;

insertv;

goto 2.

     其中定义:

(x, y, z)为根据z在x到y的向量右边、同一条直线上、或左边,而返回1, 0, -1的函数。

       push操作就是使得t = t + 1; dt = v。

     pop操作就是使得 t = t - 1。

       insert操作就是使得b = b - 1; db = v。

       remove操作就是使得b = b + 1。

29.3.1   实例

PKU JudgeOnline, 1113, Wall.

29.3.2   问题描述

已知N个点的坐标,要将这些点用围墙围起来,并使得围墙距离点的距离不超过L。求围墙的周长。输出四舍五入。

先输入N和L,然后是N个点的坐标。

1.3.3   输入

9100

200400

300400

300300

400300

400400

500400

500200

350200

200 200

29.3.4   输出

1628

29.3.5   分析

先求这些点的凸包。

可以很容易地证明:周长最短的围墙是由由于凸包的每条边,垂直向外平移L的距离,再将这些线段用半径为L的圆弧连接起来而构成的。

同时又很容易证明:这些圆弧的角度之和为360度。

故此这个问题直接转化为求凸包的周长问题。

凸包的求法中三点共线是十分需要注意的。Melkman算法描述中略去了对三点共线的许多细节的处理。

29.3.6   程序


29.4    实例

29.4.1   线段相交的实例

PKU JudgeOnline, 1039, Pipe.

29.4.2   凸包的实例

PKU JudgeOnline, 1113, Wall.

本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article


[i] Discrete Mathematics, Sixth Edition. Richard Johnsonbaugh.

[ii] On-line Construction of the Convex Hull of a Simple Polygon. MelkmanA. Information Processing Letters 25, p11-12 , (1987).