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