动态规划DP——凸多边形最优三角剖分

1.问题分析

 我们可以把披萨饼看作是一个凸多边形,凸多边形是指多边形的任意两点的连线均落在多边形的内部或边界上。

(1)什么是凸多边形?

如下图所示,是一个凸多边形

如下图所示,不是一个凸多边,因为v1v3连线落在了多边形的外部

凸多边形不相邻的两个顶点的连线称为凸多边形的弦

(2)什么是凸多边形的三角剖分?

凸多边形的三角剖分是指将一个凸多边形分割成互不相交的三角形的弦的集合。如下图所示,都是三角形的剖分,三角形的剖分有很多种:

如果我们在给定凸多边形及定义在边,弦上的权值,即任意两点之间定义一个数值作为i权值,如图所示:

三角形上权值之和是指三角形的3条边上的权值之和:

w(vi vk vj)=|vi vk| + |vk vj | + |vi vj| 

如图所示,w(v0v1v4)=|v0v1| + |v1v4| + |v0v4| = 22+8+5=15.

(3)什么是凸多边形最优三角剖分?

一个凸多边形的三角剖分有很多种,最优三角剖分就是划分的各三角形上权函数之和最小的三角剖分。

2.算法设计

 凸多边形最优三角剖分满足动态规划的最优子结构性质,可以从自底向上逐渐推出整体的最优。

(1)确定合适的数据结构

采用二维数组g[ ][ ]记录各个顶点之间的连接权值,二维数组m[ ][ ]存放各个子问题的最优值,二维数组s[ ][ ]存放各个子问题的最优策略。

(2)初始化

输入顶点数n,然后依次输入各个顶点之间的连接权值存储在二维数组g[ ][ ]中,令n=n-1(顶点标号从v0开始),

m[i][i]=0,s[i][i]=0,其中i=1,2,3,4……,n-1。

(3)循环

  • 按照递归关系式计算3个顶点{v i-1,vi,vi+1}的最优三角剖分,j=i+1,将最优值存入m[i][j],同时将最优策略存入s[i][j],i=1,2,3,……,n-1。
  • 按照递归关系式计算4个顶点{v i-1,vi,vi+1,vi+2}的最优三角剖分,j=i+2,将最优值存入m[i][j],同时将最优策略存入s[i][j],i=1,2,3,……,n-2。
  • 以此类推,直到求出所有顶点{v0,v1,v2,……,vn}的最优三角剖分,并将最优值存入m[1][n],将最优策略记入s[1][n]

(4)构造最优解

根据最优决策信息数组s[ ][ ]递归构造最优解,即输出凸多边形的最优剖分的所有弦。s[1][n],表示凸多边形最优三角剖分位置。

  • 如果子问题1为空,即没有一个顶点,说明V0Vs[1][n]是一条边,不是弦,不需要输出,否则,输出该弦V0Vs[1][n]
  • 如果子问题2为空,即没有一个顶点,说明Vs[1][n]Vn是一条边,不是弦,不需要输出,否则,输出该弦Vs[1][n]Vn
  • 递归构造两个子问题{ v0,v1,v2,……,Vs[1][n] } 和 { Vs[1][n] ,v1,v2,……,vn },一直递归到子问题为空停止。

3.源代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <sstream>
#include <algorithm>
using namespace std;

const int M =1111;
int n; //顶点数
int s[M][M];//记录最优策略二维数组
double m[M][M];//记录最优值二维数组
double g[M][M];//记录各顶点之间权值的二维数组

void convex_Polygon_Triangulation()
{
    for (int i=1;i<=n;i++) //初始化
    {
        m[i][i]=0;
        s[i][i]=0;
    }
    for(int d=2;d<=n;d++)//d为问题规模,d=2实际上有三个点
    {
        for (int i=1;i<=n-d+1;i++)//控制i值
        {
            int j=i+d-1; //j值
            m[i][j]=m[i+1][j]+g[i-1][i]+g[i][j]+g[i-1][j];
            //策略为k=i的情况
            s[i][j]=i;
            for (int k=i+1;k<j;k++) //枚举划分点i到j所有情况
            {
                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)
    {
        cout << "{v" << i-1 << "v" << s[i][j] << "}" << endl;
    }
    if(s[i][j]+1<j)
    {
        cout << "{v" << s[i][j] << "v" << j << "}" << endl;
    }
    print(i,s[i][j]);
    print(s[i][j]+1,j);
}

int main()
{
    int i;
    int j;
    cout << "请输入顶点个数n:"<< endl;
    cin >> n;
    n--;
    cout << "请依次输入各顶点的连接权值:" << endl;
    for (i=0;i<=n;++i)
    {
        for (j=0;j<=n;++j)
        {
            cin >> g[i][j];
        }
    }
    convex_Polygon_Triangulation();
    cout << "最优三角剖分的权值和是:" << endl;
    cout << m[1][n]<< endl;
    cout << "顶点的集合是:"<< endl;
    print(1,n);
    return 0;
}

4.测试结果

 

发布了57 篇原创文章 · 获赞 9 · 访问量 3630

猜你喜欢

转载自blog.csdn.net/Jayphone17/article/details/102581362