动态规划之凸多边形最优三角剖分问题

【三角剖分】

三角剖分(Triangulation)也叫做三角化,或者分格化,就是对给定的平面点集,生成三角形集合的过程,即将复杂的多边形剖分成多个三角。

考虑平面点集P={ P1...Pn },我们希望得到三角形集合T=在{ t1...tm },满足:

a)所有三角形的端点恰好构成集合P。

b)任意两个三角形的边不相交(要么重合,要么没有交点)。

c)所有三角形的合集构成P的凸包。

【题目】

使用动态规划算法解凸多边形最优三角剖分问题,具体来说就是,依据递归式,按照顺序求得子问题,使得该三角剖分中诸三角形上权之和为最小。

[输入:] 在屏幕上输入凸多边形顶点个数和顶点坐标。按逆时针顺序输入顶点坐标。

[输出:]  最优三角剖分后的三角形顶点。

【问题分析】

【最优子结构性质】

凸多边形的最优三角剖分问题有最优子结构性质

若凸(n+1)边形P=<v0 ,v1 ,… ,vn>的一个最优三角剖分T包含三角形v0 vk vn ,1≤k≤n-1,则T的权为3个部分权的和,即三角形v0 vk vn的权,子多边形<v0 ,v1 ,… ,vk>的权和<vk ,vk+1 ,… ,vn>的权之和。由T所确定的这两个子多边形的三角剖分也是最优的,因为若有<v0 ,v1 ,… ,vk>或<vk ,vk+1 ,… ,vn>的更小权的三角剖分,将会导致T不是最优三角剖分的矛盾。

【最优三角剖分的递归结构】

定义t[i,j],1≤i<j≤n,为凸子多边形<vi-1 ,vi ,… ,vj>的最优三角剖分所对应的权值,即最优值。
设退化的多边形<Vi-1 ,vi>权值为0,那么凸(n+1)边形对应的权的最优值为t[1,n]。
t[i,j]的值可以利用最优子结构性质递归地计算。由于退化的2顶点多边形的权值为0,所以t[i,i]=0,i=1,2,…,n 。当j-i≥1时,子多边形<vi-1 ,vi ,… ,vj>至少有3个顶点。

由最优子结构性质,t[i,j]的值应为t[i,k]的值加上t[k+1,j]的值,再加上vi-1 vk vj的权值,并在i≤k≤j-1的范围内取最小。由此,t[i,j]可递归地定义为:

【计算最优值】

计算凸(n+1)边形P=<v0 ,v1 ,… ,vn>的三角剖分最优权值的动态规划算法,输入是凸多边形P=<v0 ,v1 ,… ,vn>的权函数ω,输出是最优值t[i,j]和使得t[i,k]+t[k+1,j]+ω(△vi-1vkvj)达到最优的位置(k=)s[i,j],1≤i≤j≤n 。

【构造最优三角剖分】

对于任意的1≤i≤j≤n ,上述算法在计算每一个子多边形<vi-1 ,vi ,… ,vj>的最优三角剖分所对应的权值t[i,j]的同时,还在s[i,j]中记录了此最优三角剖分中与边(或弦)vi-1vj构成的三角形的第三个顶点的位置。

因此,利用最优子结构性质并借助于s[i,j],1≤i≤j≤n ,凸(n+l)边形P=<v0 ,v1 ,… ,vn>的最优三角剖分可容易地在Ο(n)时间内构造出来

【C++代码实现】

#include<bits/stdc++.h>
using namespace std;

const int N = 7; //凸多边形边数+1
int weight[][N] = {{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  MinWeightTriangulation(int n, int **t, int **s);//此多边形的最优三角剖分值
void Traceback(int i, int j, int **s);  //构造最优解
int Weight(int a, int b, int c);        //权函数

int main()
{
    int **s = new int *[N];
    int **t = new int *[N];
    for(int i=0; i<N; i++)
    {
        s[i] = new int[N];
        t[i] = new int[N];
    }
    cout<<"此多边形的最有三角剖分值为:"<<MinWeightTriangulation(N-1, t, s)<<endl;
    cout<<"最优三角剖分结构为:"<<endl;
    Traceback(1, 5, s);       //s[i][j]记录了Vi-1和Vj构成三角形的第三个顶点的位置
    system("pause");
    return 0;
}
int 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)  //r表示凸子多边形的顶点数
        for(int i=1; i<=n-r+1; ++i)
        {
            int j = i+r-1;
            t[i][j] = t[i+1][j] + Weight(i-1, i, j);
            s[i][j] = i;
            for(int k=i+1; k<i+r-1; k++)
            {
                int u = t[i][k] + t[k+1][j] + Weight(i-1, k, j);
                if(u<t[i][j])
                {
                    t[i][j] = u;
                    s[i][j] = k;
                }
            }
        }
    return  t[1][N-2];
}
void Traceback(int i, int j, int **s)
{
    if(i==j) return;
    Traceback(i, s[i][j], s);
    Traceback(s[i][j]+1, j, s);
    cout<<"三角剖分顶点:V"<<i-1<<",V"<<j<<",V"<<s[i][j]<<endl;
}
int Weight(int a, int b, int c)
{
    return weight[a][b] + weight[b][c] + weight[a][c];
}

运行截图:

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值