临近图
一系列的具有临近关系的图
DT是他们的超图
可以先计算出DT然后在计算出这些重要的图
整体关系
DT >= GG >= RNG >= EMST >= NNG
0、Delaunay Triangulation(DT)
定义
德劳内三角剖分
唯一生成的
任意相邻两点构成的直线,定是某空圆的弦
同样是三角剖分,得老内剖分的结果:是一种使最小角达到最大的三角剖分
算法
//德劳内三角剖分 RIC算法
#include
using namespace std;
// 代表一个点
struct Point {
int X;
int Y;
};
// 代表一个三角形
struct Trangle {
Point a, Point b, Point c;
};
// 返回德劳内图形DT中某点P所在的三角形 (会用到DCEL结构)
T TriangleContaining (Polyline DT, Point P) {
//这里用一个桶来存储其中所有的点,每个桶的外边界就是一个已经剖分过的三角形
}
//找到与abc构成三角形的右边的三角形中ab边对应的点x
Point RightSite(Point a, Point b) {
//使用DCEL 既b\a边所在三角形中的另一个顶点
//没有返回null
}
//查看x是否在p、a、b三点构成的内接圆中
int InCircle(Point p, Point a, Point b, Point x) {
//一个行列式 关于 a\b\x\p的四阶行列式
//优点:没有除法,速度O(1)
return f(pabx); //大于0表示在圆内,小于表示在圆形外
}
//用ab替换px
void FlipEdge(Point a, Point b, Point p, Point x) {
//这里面要操作的结构是要改变上面的存储桶三角形所包含点的位置
//原本四边形p a x b可分割为T(p, a, b)&T(a, b, x),现在分割为T(p, a, x) & T(p, b, x)
}
//测试固定a、b两点,与p构成的外接圆是否为空圆(圆内不存在任何点)
//如果不为空圆,则修改为最优(使用了递归)
void STest(Point p, Point a, Point b) {
//获取从a到b直线右边的那个点(利用DCEL的双向结构)
//(与a、b所在线段构成三角形(会有左右两个)右边的那个顶点)
Point x = RightSite(a, b);
//如果不存在点x在ab右侧,即ab为多边形的边界,最简单的情况,不用处理
if(!x) return;
//查看x是否在p、a、b三点构成的内接圆中
if(InCircle(p, a, b, x) > 0) {
//用ab替换px
FlipEdge(a, b, p, x);
//测试新增加的值得怀疑的两条线
STest(p, a, x);
STest(p, x, b);
}
}
//德劳内三角形的递归做法
//测试并修复图中可疑的pa、pb、pc线(因为可能破坏结构不符合空圆要求)
void SwapTest(Point p, Point a, Point b, Point c) {
STest(p, a, b);
STest(p, b, c);
STest(p, c, a);
}
//德劳内三角剖分的递推做法
//只需改变递归做法中的反转测试
SwapTest(p, a, b, c) {
queue q = {(a, b), (b, c), (c, a)};
wahile(!q.empty()) {
(a, b) = q.dequeue();
Point x = RightSite(a, b);//find t(a,x,b) on opposite side(using DCEL)
if(!x) connect; //in case x doesnot exist
if(InCircle(p, a, b, x)) { //if x voilates in-circle condition
FlipEdge(a, b, p, x);//replace ab with px and
Q.enqueue((a, x), (x, b));//insert the 2 new triangles
}
}
}
//在已经正确的德劳内图形中插入点P
void Insert (Point p) {
//首先找到包含P这个点的三角形(P在哪个三角形内部)
Trangle T(a, b, c) = TriangleContaining(DT, p);
//链接pa、pb、pc三条线 并插入到德劳内三角剖分图形中
connect(p, a);
connect(p, b);
connect(p, c);
//测试并修复图中可疑的pa、pb、pc线(因为可能破坏结构不符合空圆要求)
SwapTest(p, a, b, c);
}
int main() {
Point a, Point b, Point c;
//假设原本是一个超巨大的三角形
Polyline DT(a, b, c);
//不断地加入点构成更多的三角形。
//类似于建堆
for(int i = 2; i < points.size(); ++i) {
Insert(points[i]);
}
return 0;
}
关系
DT是维诺图互为对偶图
0.5、Convex Hull
定义
凸包
关系
凸包会包含所有的点
CH是DT的子图
1、Gabriel Graph(GG)
定义
任意两相连点构成的直线为直径,这个圆是空圆
关系
GG是DT的子图
GG是连通图
2、Relative Neighborhood Graph(RNG)
定义
相对邻居图
任意两相连点P、Q,p为圆心半径到q的圆,以及q为圆心同样半径的圆,相交部分是空的(不含有其他点)
关系
RNG是GG子图
RNG是连通图
3、Euclidean Minimum Spanning Tree (EMST)
定义
欧式最小生成树
Euclidean
所有点都应当属于一个欧氏空间
任意两点之间的权重就是其欧氏距离
使所有点 连通且最权重最小的生成树
如果直接去求,那么点之间两两都有距离,就是一个完全图(N^2条边),可以通过DT使边减少为N的常数倍
然后依旧是正常的最小生成树算法
克鲁斯卡尔O(n * n * logn)
普利姆O(n * n)
关系
EMST是RNG的子图
反证法
EMST是连通图
EMST没有环路
4、Nearest Neighbour Graph(NNG)
定义
最近邻图
每个点指向离它最近的那个点
关系
NNG是EMST的子图
NNG可能不连通(Forest)
NNG有向
5、拓展
Minimum Weighted Triangulation(MWT)
定义
最小权重三角划分
每个三角形三边之和尽可能的小
关系
此算法和德劳内三角划分区分开来
这个问题是NP-complete的
Euclidean Traveling Salesman Problem
定义
欧式旅行商问题
是一种NP—Hard问题
关系
但是可以快速获得一个次优的解,这个次优近似解最差也是最优解的两倍以内
算法
首先生成EMST,利用DCEL遍历EMST并生成环路,遇到见过的就跳过
ps:有一种1.5倍次优解,但是算法难度较大