凸多边形最优三角剖分
题目:
多边形是平面上一条分段线性的闭曲线。凸多边形满足:边界上或内部的任意两点所连成的直线段上所有点均在凸多边形内部或边界上。通常用多边形顶点的逆时针序列表示凸多边形,即 P = { v 0 , v 1 , . . . , v n − 1 } P=\{v_0,v_1,...,v_{n-1}\} P={v0,v1,...,vn−1} 表示具有n条边 v 0 v 1 、 v 1 v 2 、 . . . 、 v n − 1 v n v_0v_1、v_1v_2、...、v_{n-1}v_{n} v0v1、v1v2、...、vn−1vn 的凸多边形。其中,约定 v 0 = v n v_0=v_n v0=vn 。
若 v i v_i vi 与 v j v_j vj 是多边形上不相邻的两个顶点,则线段 v i v j v_iv_j vivj 称为多边形的一条弦。弦 v i v j v_iv_j vivj 将多边形分割成两个多边形 { v i , v i + 1 , v j } \{v_i,v_{i+1},v_j\} {vi,vi+1,vj} 和 { v j , v j + 1 , v i } \{v_j,v_{j+1},v_i\} {vj,vj+1,vi} 。
多边形的三角剖分是指将多边形分割成互不相交的三角形的弦的集合T。下图就是不同的三角剖分:
规定三角形上各种各样的权值函数 w ( v i v j v k ) = ∣ v i v j ∣ + ∣ v i v k ∣ + ∣ v k v i ∣ w(v_iv_jv_k)=\vert v_iv_j \vert + \vert v_iv_k \vert + \vert v_kv_i \vert w(vivjvk)=∣vivj∣+∣vivk∣+∣vkvi∣ 。其中 ∣ v i v j ∣ \vert v_iv_j \vert ∣vivj∣ 为两点的欧氏距离,现要求出全职最小的三角剖分,即最优三角剖分。
分析:
这题类似于矩阵连乘的最优计算次序问题,等价于矩阵链的最优完全加括号方式,可以用动态规划来解。
最优子结构性质:
若 n+1
边形
P
=
{
v
0
,
v
1
,
.
.
.
,
v
n
}
P=\{v_0,v_1,...,v_n\}
P={v0,v1,...,vn} 的最优三角剖分 T
包含三角形
v
0
v
k
v
n
(
1
≤
k
≤
n
−
1
)
v_0v_kv_n \quad (1 \leq k \leq n-1)
v0vkvn(1≤k≤n−1) ,则 T
的权为三角形
v
0
v
k
v
n
v_0v_kv_n
v0vkvn 的权、子多边形
{
v
0
,
v
1
,
.
.
.
,
v
k
}
\{v_0,v_1,...,v_k\}
{v0,v1,...,vk} 和
{
v
k
,
v
k
+
1
,
.
.
.
,
v
n
}
\{v_k,v_k+1,...,v_n\}
{vk,vk+1,...,vn} 的权之和。可以断言,由 T
确定的这两个子多边形的三角剖分也是最优的。因为若存在更小权的三角剖分,将导致 T
不是最优的三角剖分,与假设矛盾。
递归定义:
定义 t[i][j] (1<=i<j<=n)
为凸子多边形
{
v
i
−
1
,
v
i
,
.
.
.
,
v
j
}
\{v_{i-1},v_i,...,v_j\}
{vi−1,vi,...,vj} 的最优三角剖分对应得权函数值。设退化的多边形
{
v
i
−
1
,
v
i
}
\{v_{i-1},v_i\}
{vi−1,vi} 具有权值0。据此定义,要计算的凸 n+1
边形 P
的最优权值为 t[1][n]
。根据上述分析,递归定义式为:
t
[
i
]
[
j
]
=
{
0
i
=
j
min
i
≤
k
≤
j
{
t
[
i
]
[
k
]
+
t
[
k
+
1
]
[
j
]
+
w
(
v
i
−
1
v
k
v
j
)
}
i
<
j
t[i][j]= \begin{cases} 0 && i=j \\ \min_{i \leq k \leq j} \{t[i][k]+t[k+1][j]+w(v_{i-1}v_kv_j)\} && i<j \end{cases}
t[i][j]={0mini≤k≤j{t[i][k]+t[k+1][j]+w(vi−1vkvj)}i=ji<j
实现:
计算权值:
/**
凸多边形最优三角剖分
n: 顶点个数
t: 剖分的权值矩阵
s: 剖分路径矩阵
*/
void minWeightTriangulation(int n, int **t, int **s){
// 初始化对角线位置
for(int i=1; i<=n; i++){
t[i][i] = 0;
}
// 斜对角线索引
for(int r=2; r<=n; r++){
// 行
for(int i=1; i<=n-r+1; i++){
// 列
int j = i + r - 1;
// 将权重初始化为 {v_i, v_i} {v_i, v_i+1,..., v_j}时的权重
t[i][j] = t[i+1][j] + w(i-1, i, j);
s[i][j] = i;
// 寻找最大切分点
for(int k=i+1; k<j; k++){
int u = t[i][k] + t[k+1][j] + w(i-1, k, j);
if(u < t[i][j]){
t[i][j] = u;
s[i][j] = k;
}
}
}
}
}
**计算权重策略:**根据题目定义,这边未给出明确的方法
/*
权重策略
根据题目定义,这边未给出明确的方法
i: vi
k: vk
j: vj
*/
int w(int i, int k, int j){
return 0;
}
构造最优剖分:
s[i][j]
记录着与
v
i
−
1
v_{i-1}
vi−1 和
v
i
v_{i}
vi 一起构成三角形的第三个顶点位置,即切分点。寻找最优剖分可以类似矩阵连乘中寻找最优结合的方法,即找到剖点后依次向两边递归即可。