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

【题目描述】
凸多边形最优三角剖分问题要求将凸多边形分割为互不相交的三角形,使得所有三角形的权值之和最小。每个三角形的权值由其三个顶点构成的边的权值之和决定。

给定一个 ​n 个顶点的凸多边形(顶点按顺时针或逆时针顺序编号为 ​V₀, V₁, ..., Vₙ₋₁)和顶点间的权值矩阵,求最优三角剖分的最小权值和,并输出所有剖分三角形的顶点组合。


输入格式

  • 第一行为整数 ​n​(3 ≤ n ≤ 20),表示顶点数。
  • 接下来 ​n 行,每行 ​n 个整数,表示权值矩阵。其中第 ​i 行第 ​j 列的值为顶点 ​Vᵢ₋₁ 到 ​Vⱼ₋₁ 的权值(矩阵保证对称,对角线为0)。

输出格式

  • 第一行输出最小权值和。
  • 后续每行输出一个三角形的顶点组合,格式为 ​Vi,Vj,Vk​(i < j < k),按剖分构造顺序排列。

输入样例

6  
0 2 3 1 5 6  
2 0 3 4 8 6  
3 3 0 10 13 7  
1 4 10 0 12 5  
5 8 13 12 0 3  
6 6 7 5 3 0  

输出样例

57  
V0,V5,V3  
V0,V3,V1  
V3,V5,V4 

代码

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

const int N = 25; // 最大顶点数
int g[N][N];     // 权值矩阵
int dp[N][N];    // 动态规划表
int s[N][N];     // 记录剖分点

// 计算三角形的权值
int weight(int a, int b, int c) {
    return g[a][b] + g[b][c] + g[a][c];
}

// 动态规划求解最优三角剖分
int minWeightTriangulation(int n) {
    for (int len = 2; len <= n - 1; len++) { // 子问题规模
        for (int i = 1; i <= n - len; i++) { // 子问题起点
            int j = i + len; // 子问题终点
            dp[i][j] = INT_MAX; // 初始化为最大值
            for (int k = i + 1; k < j; k++) { // 枚举剖分点
                int cost = dp[i][k] + dp[k][j] + weight(i, k, j);
                if (cost < dp[i][j]) {
                    dp[i][j] = cost;
                    s[i][j] = k; // 记录剖分点
                }
            }
        }
    }
    return dp[1][n];
}

// 递归输出剖分三角形的顶点组合
void traceback(int i, int j) {
    if (i + 1 >= j) return; // 无法再剖分
    int k = s[i][j]; // 剖分点
    cout << "V" << i - 1 << ",V" << j - 1 << ",V" << k - 1 << endl; // 输出三角形
    traceback(i, k); // 递归左半部分
    traceback(k, j); // 递归右半部分
}

int main() {
    int n;
    cin >> n;

    // 输入权值矩阵
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> g[i][j];
        }
    }

    // 初始化动态规划表
    for (int i = 1; i <= n; i++) {
        dp[i][i] = 0; // 单个顶点无法剖分
    }

    // 计算最小权值和
    int minWeight = minWeightTriangulation(n);
    cout << "最小权值和: " << minWeight << endl;

    // 输出剖分三角形的顶点组合
    cout << "剖分三角形顶点组合:" << endl;
    traceback(1, n);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值