算法:凸多边形最优三角剖分

算法:凸多边形最优三角剖分1 问题相关定义 1 凸多边形的三角剖分 将凸多边形分割成互不相交的三角形的弦的集合 T 2 最优剖分 给定凸多边形 P 以及定义在由多边形的边和弦组成的三角形上的权函数 w 要求确定该凸多边形的三角剖分 使得该三角剖分中诸三角形上权之和为最小 凸多边形三角剖分如下图所示 2 最优子结构性质 若凸 n 1 边形 P V0 V1 Vn 的最优三角剖分 T 包含三角形

1、问题相关定义:

 (1)凸多边形的三角剖分:将凸多边形分割成互不相交的三角形的弦的集合T。 (2)最优剖分:给定凸多边形P,以及定义在由多边形的边和弦组成的三角形上的权函数w。要求确定该凸多边形的三角剖分,使得该三角剖分中诸三角形上权之和为最小。 凸多边形三角剖分如下图所示: 

在这里插入图片描述

 2、最优子结构性质: 若凸(n+1)边形P={V0,V1……Vn}的最优三角剖分T包含三角形V0VkVn,1<=k<=n,则T的权为三个部分权之和:三角形V0VkVn的权,多边形{V0,V1……Vk}的权和多边形{Vk,Vk+1……Vn}的权之和。如下图所示: 

在这里插入图片描述

 可以断言,由T确定的这两个子多边形的三角剖分也是最优的。因为若有{V0,V1……Vk}和{V0,V1……Vk}更小权的三角剖分,将导致T不是最优三角剖分的矛盾。因此,凸多边形的三角剖分问题具有最优子结构性质。 3、递推关系: 设t[i][j],1<=i<j<=n为凸多边形{Vi-1,Vi……Vj}的最优三角剖分所对应的权值函数值,即其最优值。最优剖分包含三角形Vi-1VkVj的权,子多边形{Vi-1,Vi……Vk}的权,子多边形{Vk,Vk+1……Vj}的权之和。 

在这里插入图片描述

 因此,可得递推关系式: 

在这里插入图片描述

 凸(n+1)边形P的最优权值为t[1][n]。 

在这里插入图片描述
在这里插入图片描述
详细解析:
(1)什么是凸多边形?


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

在这里插入图片描述

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

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

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

在这里插入图片描述

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

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

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

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

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

在这里插入图片描述

 凸多边形最优三角剖分满足动态规划的最优子结构性质,可以从自底向上逐渐推出整体的最优。 (1)确定合适的数据结构 采用二维数组weight[ ][ ]记录各个顶点之间的连接权值,二维数组t[ ][ ]存放各个子问题的最优值,二维数组s[ ][ ]存放各个子问题的最优策略。 (2)初始化 输入顶点数n,然后依次输入各个顶点之间的连接权值存储在二维数组weight[ ][ ]中,令n=n-1(顶点标号从v0开始), t[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,将最优值存入t[i][j],同时将最优策略存入s[i][j],i=1,2,3,……,n-1。 按照递归关系式计算4个顶点{ 
   v i-1,vi,vi+1,vi+2}的最优三角剖分,j=i+2,将最优值存入t[i][j],同时将最优策略存入s[i][j],i=1,2,3,……,n-2。 以此类推,直到求出所有顶点{ 
   v0,v1,v2,……,vn}的最优三角剖分,并将最优值存入t[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 },一直递归到子问题为空停止。 

在这里插入图片描述
源代码:

#include<bits/stdc++.h> using namespace std; const int M =1111; int n; //顶点数 int s[M][M];//记录最优策略二维数组 double t[M][M];//记录最优值二维数组 double weight[M][M];//记录各顶点之间权值的二维数组 void MinWeightTriangulation() { 
    for (int i=1;i<=n;i++) //初始化 { 
    t[i][i]=0; s[i][i]=0; } for(int r=2;r<=n;r++)//r为问题规模,r=2实际上有三个点 r为当前计算的链长(子问题规模)  { 
    for (int i=1;i<=n-r+1;i++)//n-r+1为最后一个r链的前边界  { 
    int j=i+r-1; //计算前边界为r,链长为r的链的后边界  t[i][j]=t[i+1][j]+weight[i-1][i]+weight[i][j]+weight[i-1][j];//将链ij划分为A(i) * ( A[i+1:j] )这里实际上就是k=i //策略为k=i的情况 s[i][j]=i; for (int k=i+1;k<j;k++) //枚举划分点i到j所有情况 { 
    //将链ij划分为( A[i:k] )* (A[k+1:j]) double u=t[i][k]+t[k+1][j]+weight[i-1][k]+weight[k][j]+weight[i-1][j]; if(t[i][j]>u) { 
    t[i][j]=u; s[i][j]=k; } } } } } void Traceback(int i,int j) //递归求解所有子问题的弦。 { 
    if(i==j) return ; Traceback(i,s[i][j]); Traceback(s[i][j]+1,j); cout<<"三角剖分顶点:V"<<i-1<<",V"<<j<<",V"<<s[i][j]<<endl; } 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 >> weight[i][j]; } } MinWeightTriangulation(); cout << "最优三角剖分的权值和是:" << endl; cout << t[1][n]<< endl; cout << "三角剖分顶点:"<< endl; Traceback(1,n); return 0; } 

在这里插入图片描述
在这里插入图片描述
运行效果1:
在这里插入图片描述
运行效果2:在这里插入图片描述



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233830.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Python lambda和reduce函数

    Python lambda和reduce函数

    2022年1月26日
    42
  • git clone与git pull区别

    git clone与git pull区别原地址最近一直焦虑换工作与面试,自然面试过程中也被问到了很多问题,在一家公司中,被问到了git相关的知识。面试官提出了gitclone与gitpull有什么区别。由于自己对git的掌握情况不是特别深入,感觉瞬间被问蒙圈一样。后来,查了相关的文档,看了一些文章,自己有了一丁点的理解,觉得应该…

    2022年7月21日
    13
  • .dll反编译(反编译什么意思)

    需求:有些Dll文件我们找不到源码,只有编译后的dll,但是我们想要改某个字段或者连接字符串,并不需要动太多业务逻辑的情况下,我们可以这样干。1.打开微软提供的反编译工具ildasm.exe这个工具是windows自带的反编译工具。路径:C:\ProgramFiles(x86)\MicrosoftSDKs\Windows\v10.0A\bin\NETFX4.6.2Tools可以根据需要,选择对应工具版本。一般随便选一个版本都是可以的了。比如,我选择的是4.6…

    2022年4月12日
    55
  • 微信小程序提交订单支付

    微信小程序提交订单支付主要是前端支付的几个部分**1.首先我们需要登录**通过wx.login这个api获取到code值,获取到code值后,我们请求登录的url并且把获取到的code拼接到url上,后台接收code值,登录成功后,返回openid,然后我们把获取到的openid存取到app.globalData里面2.我们支付点击按钮自己定义了一个方法pay()在方法里获取存在app.globalData里的openid然后通过支付的接口把openid传到后台返回参数res然后我们请求wx.request

    2022年6月3日
    65
  • Python静态代码检查工具Flake8

    Python静态代码检查工具Flake8flake8

    2022年9月13日
    1
  • Go语言代理proxy设置「建议收藏」

    Go语言代理proxy设置「建议收藏」关于GoproxyGOPROXY由于国内的网络环境,我们可以通过配置GOPROXY避免DNS污染导致的模块拉取缓慢或失败的问题,加速你的构建代理链接阿里云GoModule代理仓库服务Goproxy中国配置方法打开你的终端并执行:$goenv-wGOPROXY=https://goproxy.cn,direct完成。macOS或Linux打开你的终端并执行:$exportGOPROXY=https://goproxy.cn或者$echo“exportG

    2022年7月26日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号