凸多边形最优三角剖分的两种算法分析
2017-03-28 15:19
375 查看
/* Name: Copyright: Author: 巧若拙 Date: 27-03-17 10:11 Description: 动态规划--凸多边形最优三角剖分 题目描述: 用多边形顶点的逆时针序列表示凸多边形,即P={v0,v1,…,vn-1}表示具有n条边的凸多边形。 给定凸多边形P,以及定义在由多边形的边和弦组成的三角形上的权函数w。要求确定该凸多边形的三角剖分, 使得即该三角剖分中诸三角形上权之和为最小。 解题思路: 若凸(n+1)边形P={v0,v1,…,vn}的最优三角剖分T包含三角形v0vkvn,1≤k≤n-1,则T的权为3个部分权的和: 三角形v0vkvn的权,子多边形{v0,v1,…,vk}和{vk,vk+1,…,vn}的权之和。 可以断言,由T所确定的这2个子多边形的三角剖分也是最优的。 因为若有{v0,v1,…,vk}或{vk,vk+1,…,vn}的更小权的三角剖分将导致T不是最优三角剖分的矛盾。 那么我们定义一个m[i][j],0<=i<=j<N,为凸子多边形{vi,vi+1,…,vj}的最优三角剖分所对应的权函数值,即其最优值。 据此定义,要计算的凸(n+1)边形P的最优权值为m[0] 。 m[i][j]的值可以利用最优子结构性质递归地计算。当j-i>1时,凸子多边形至少有3个顶点。 由最优子结构性质,m[i][j]的值应为m[i][k]的值加上m[k][j]的值,再加上三角形vivkvj的权值,其中i<k<j。 由于在计算时还不知道k的确切位置,而k的所有可能位置只有j-i个, 因此可以在这j-i个位置中选出使m[i][j]值达到最小的位置。 由此,m[i][j]可递归地定义为: m[i][j] = 0 (i == j || i+1 == j),只有一个或两个点,不能构造三角形 m[i][j] = min{m[i][k] + m[k][j] + w(vi,vk,vj)} (i < k < j) 对于要求的m[0] ,可以用通过由下至上的,从链长(多边形的边)为2开始计算,每次求m[i][j]的最小值, 并且记录最小值所对应的K值,根据最优子结构的性质,逐步向上就可以求出m[0] 的最小值。 */ #include<iostream> using namespace std; int MinWeightTriangulation(int i, int j);//自顶向下,使用备忘录数组的动态规划算法 int MinWeightTriangulation_2(int n);//自底向上的动态规划算法 int GetWeight(int i, int k, int j);//计算三角形的周长 void PrintTriangulation(int i, int j); //输出组成最优解的各个三角形的周长 const int N = 6; int w = {{0,2,2,3,1,4}, {2,0,1,5,2,3}, {2,1,0,2,1,4}, {3,5,2,0,6,2}, {1,2,1,6,0,1}, {4,3,4,2,1,0}};//图的邻接矩阵 int m ; //m[i][j]表示多边形{Vi-1VkVj}的最优权值 int s ; //s[i][j]记录Vi-1到Vj最优三角剖分的中间点K int main(int argc, char **argv) { cout << MinWeightTriangulation(0, N-1) << endl; cout << MinWeightTriangulation_2(N-1) << endl; PrintTriangulation(0, N-1); //输出组成最优解的各个三角形的周长 system("pause"); return 0; } int MinWeightTriangulation(int i, int j)//自顶向下,使用备忘录数组的动态规划算法 { if (m[i][j] != 0) //默认为0 return m[i][j]; if (i == j || i+1 == j) return 0; //先处理k=i+1的情形,注意我们取顶点vi为起点 m[i][j] = MinWeightTriangulation(i+1, j) + GetWeight(i, i+1, j); //MinWeightTriangulation(i, i)==0,就不写了 s[i][j] = i+1; //再处理i+1<k<j的情形 for (int k=i+2; k<j; k++) { int t = MinWeightTriangulation(i, k) + MinWeightTriangulation(k, j) + GetWeight(i, k, j); if (t < m[i][j]) { m[i][j] = t; s[i][j] = k; } } return m[i][j]; } int MinWeightTriangulation_2(int n)//自底向上的动态规划算法 { m = 0; for (int i=0; i<n; i++) //只有1个点或2个点均不能构成凸多边形 m[i][i] = m[i][i+1] = 0; for (int r=2; r<n; r++)//r为当前计算的链长(子问题规模) { for (int i=0; i<=n-r; i++) //n-r为最后一个r链的前边界 { int j = i + r; //计算前边界为i,链长为r的链的后边界j,注意我们取顶点vi为起点 //先处理k=i+1的情形 m[i][j] = m[i][i+1] + m[i+1][j] + GetWeight(i, i+1, j); s[i][j] = i+1; //再处理i+1<k<j的情形 for (int k=i+2; k<j; k++) { int t = m[i][k] + m[k][j] + GetWeight(i, k, j); if (t < m[i][j]) { m[i][j] = t; s[i][j] = k; } } // cout << "m["<<i<<"]["<<j<<"]= " << m[i][j] << " "; } //cout << endl; } return m[0] ; } int GetWeight(int i, int k, int j)//计算三角形的周长 { return w[i][k] + w[k][j] + w[j][i]; } void PrintTriangulation(int i, int j) //输出组成最优解的各个三角形的周长 { if (i == j || i+1 == j) return; PrintTriangulation(i, s[i][j]); cout << "V" << i << "-V" << s[i][j] << "-V" << j << " = " << GetWeight(i, s[i][j], j) << endl; PrintTriangulation(s[i][j], j); }
算法2来自于王晓东老师编著的《计算机算法设计与分析》,它与算法1的基本思路是一样的,但做了一些简化处理,考虑到顶点数少于3个时是无法构成三角形的,算法2设置退化的多边形{vi-1,vi}具有权值为0,那我们在考虑最优解时,就不需要从顶点v0开始,而是从顶点v1开始,这样要计算的凸(n+1)边形P的最优权值为m[1]
。
需要注意的是,我们在求m[i][j]的时候,是取顶点vi-1为起点的,所以计算三角形的权之和(周长)时,我们计算的是GetWeight(i-1, k, j)。这和算法1是不一样的。
总的来说,算法1直观,算法2 简洁。
#include<iostream>
using namespace std;
int MinWeightTriangulation(int i, int j);//自顶向下,使用备忘录数组的动态规划算法
int MinWeightTriangulation_2(int n);//自底向上的动态规划算法
int GetWeight(int i, int k, int j);//计算三角形的周长
void PrintTriangulation(int i, int j); //输出组成最优解的各个三角形的周长
const int N = 6;
int w
= {{0,2,2,3,1,4},
{2,0,1,5,2,3},
{2,1,0,2,1,4},
{3,5,2,0,6,2},
{1,2,1,6,0,1},
{4,3,4,2,1,0}};//图的邻接矩阵
int m
; //m[i][j]表示多边形{Vi-1VkVj}的最优权值
int s
; //s[i][j]记录Vi-1到Vj最优三角剖分的中间点K
int main(int argc, char **argv)
{
cout << MinWeightTriangulation(1, N-1) << endl;
cout << MinWeightTriangulation_2(N-1) << endl;
PrintTriangulation(1, N-1); //输出组成最优解的各个三角形的周长
system("pause");
return 0;
}
int MinWeightTriangulation(int i, int j)//自顶向下,使用备忘录数组的动态规划算法
{
if (m[i][j] != 0) //默认为0
return m[i][j];
if (i == j)
return 0;
//先处理k=i的情形,注意我们取顶点vi-1为起点
m[i][j] = MinWeightTriangulation(i+1, j) + GetWeight(i-1, i, j); //MinWeightTriangulation(i, i)==0,就不写了
s[i][j] = i;
//再处理i<k<j的情形
for (int k=i+1; k<j; k++)
{
int t = MinWeightTriangulation(i, k) + MinWeightTriangulation(k+1, j) + GetWeight(i-1, k, j);
if (t < m[i][j])
{
m[i][j] = t;
s[i][j] = k;
}
}
return m[i][j];
}
int MinWeightTriangulation_2(int n)//自底向上的动态规划算法
{
for (int i=1; i<=n; i++)
m[i][i] = 0;
for (int r=2; r<=n; r++)//r为当前计算的链长(子问题规模)
{
for (int i=1; i<=n-r+1; i++) //n-r+1为最后一个r链的前边界
{
int j = i + r - 1; //计算前边界为i,链长为r的链的后边界j,注意我们取顶点vi-1为起点
//先处理k=i的情形
m[i][j] = m[i][i] + m[i+1][j] + GetWeight(i-1, i, j);
s[i][j] = i;
//再处理i<k<j的情形
for (int k=i+1; k<j; k++)
{
int t = m[i][k] + m[k+1][j] + GetWeight(i-1, k, j);
if (t < m[i][j])
{
m[i][j] = t;
s[i][j] = k;
}
}
}
}
return m[1]
;
}
int GetWeight(int i, int k, int j)//计算三角形的周长
{
return w[i][k] + w[k][j] + w[j][i];
}
void PrintTriangulation(int i, int j) //输出组成最优解的各个三角形的周长
{
if (i == j)
return;
PrintTriangulation(i, s[i][j]);
cout << "V" << i-1 << "-V" << s[i][j] << "-V" << j << " = " << GetWeight(i-1, s[i][j], j) << endl;
PrintTriangulation(s[i][j]+1, j);
}
相关文章推荐
- 算法笔记——【动态规划】凸多边形最优三角剖分
- 计算几何---多边形三角剖分算法研究与实现
- 算法竞赛入门经典 例题 9-7 最优三角剖分
- 后缀数组两种算法的分析比较
- 二分图的两种算法-最大匹配与最优匹配 poj--1469,2536
- 凸多边形最优三角剖分
- 凸多边形最优三角剖分
- MySQL查询优化器源码分析--多表连接优化算法之三,greedy_search(),搜索表之间的各种组合以得到最优的查询计划
- 动态规划--凸多边形最优三角剖分
- 【动态规划】凸多边形最优三角剖分
- MySQL查询优化器源码分析--多表连接优化算法之一,optimize_straight_join()按表的指定顺序求解最优查询计划
- 凸多边形最优三角剖分问题
- 动态规划--凸多边形最优三角剖分
- —【动态规划】凸多边形最优三角剖分
- 凸多边形最优三角剖分-动态规划
- 【算法分析】三维曲面的三角剖分算法分析
- 动态规划;多边形游戏;类似圈型石头合并;算法设计分析作业;
- 凸多边形最优三角剖分问题
- 凸多边形最优三角剖分
- Spark资源调度机制源码分析--基于spreadOutApps及非spreadOutApps两种资源调度算法