凸多边形的三角剖分:将一个凸多边形分割成互不相交的三角形的弦的集合。
最优三角剖分:划分的各三角形上权函数之和最小的三角剖分。
证明是否具有最优子结构性质:
(1)分析最优解的结构特征
假设在第k个顶点切开会得到最优解,那么原问题就变成了两个子问题和一个三角形,子问题分别是和,三角形为
证明:原问题的最优解包含子问题的最优解。
假设三角剖分的权值之和是c,三角剖分的权值之和是a,三角剖分的权值之和是b,三角形的权值之和是,那么c=a+b+。因此证明如果c是最优的,则a和b一定是最优的。
反证法:
如果a不是最优的,三角剖分一定存在一个最优解a',a'<a,那么a'+b+<c,所以c不是最优的,这与假设c是最优的矛盾。因此,如果c是最优的,则a和b一定是最优的。
(2)建立最优值的递归式
用m[i][j]表示凸多边形三角剖分的最优值,那么两个子问题、对应的最优值分别是m[i][k]、m[k+1][j],剩下的就是三角形的权值之和是
凸多边形三角剖分最优解递归式:
(3)自底向上计算并记录最优值
先求只有3个顶点凸多边形三角剖分的最优值,再求4个,直到n个。
(4)构造最优解
需要从记录表中还原部分次序,找到最优剖分的弦,由这些弦构造出最优解。
算法设计:
(1)确定合适的数据结构
采用g[][]记录各个顶点之间的连接权值,m[][]存放各个子问题的最优值,s[][]存放各个子问题的最优策略。
(2)初始化
令n=n-1(顶点标号从v0开始),m[i][i]=0,s[i][i]=0。
(3)循环阶段
按照递归关系式计算3个顶点的最优三角剖分,j=i+1,将最优值存入m[i][j],同时最优策略记入s[i][j]。
以此类推,直到求出所有顶点的最优三角剖分,并将最优值存入m[1][n],将最优策略记入s[1][n]。
(4)构造最优解
根据最优决策信息数组s[][]递归构造最优解,即输出凸多边形最优剖分的所有弦。s[1][n]表示凸多边形的最优三角剖分位置。
- 如果子问题1为空,即没有一个顶点,说明是一条边,不是弦,不需输出,否则输出。
- 如果子问题2为空,即没有一个顶点,说明是一条边,不是弦,不需输出,否则输出。
- 递归构造两个子问题,直到子问题为空。
示例代码:
#include <iostream>
#include <sstream>
#include <cmath>
#include <algorithm>
using namespace std;
const int M=1000+5;
int n;
int s[M][M];
double m[M][M],g[M][M];
void Convexpolygontriangulation(){
for(int i=1;i<=n;i++){
m[i][i]=0;
s[i][i]=0;
}
for(int d=2;d<=n;d++)
for(int i=1;i<=n-d+1;i++){
int j=i+d-1;
m[i][j]=m[i+1][j]+g[i-1][i]+g[i][j]+g[i-1][j]; //子问题2 m[i+1][j]
s[i][j]=i;
for(int k=i+1;k<j;k++){
double temp=m[i][k]+m[k+1][j]+g[i-1][k]+g[k][j]+g[i-1][j];
if(m[i][j]>temp){
m[i][j]=temp;
s[i][j]=k;
}
}
}
}
void print(int i,int j){
if(i==j) return;
if(s[i][j]>i) //表示i到s[i][j]之间存在顶点,子问题1不为空
cout<<"{v"<<i-1<<"v"<<s[i][j]<<"}"<<endl;
if(j>s[i][j]+1) //表示s[i][j]+1到j之间存在顶点,子问题2不为空
cout<<"{v"<<s[i][j]<<"v"<<j<<"}"<<endl;
print(i,s[i][j]);
print(s[i][j]+1,j);
}