【区间dp】-----例题4【凸多边形的划分】
凸多边形的划分
题目描述
给定一个具有 N 个顶点的凸多边形,将顶点从 1 至 N 标号,每个顶点的权值都是一个正整数。
将这个凸多边形划分成 N-2 个互不相交的三角形,求所有这些三角形顶点权值乘积之和的最小值。
输入描述
- 第一行输入一个整数 N,表示顶点个数。
- 第二行输入 N 个整数,依次为顶点 1 至顶点 N 的权值。
输出描述
输出仅一行,为这些三角形顶点权值乘积和的最小值。
示例
输入
5
121 122 123 245 231
输出
12214884
备注
- 对于 100% 的数据,有 N ≤ 50。
- 每个顶点的权值均小于 10^9。
AC代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using lll = __int128; // 定义 __int128 类型别名,方便使用// __int128 的打印函数:
// 标准库不支持直接打印 __int128,因此需要自定义打印函数
void print128(lll x) {if (x == 0) // 特判0{cout << '0';return;}if (x < 0) // 处理负数,先打印负号,再取正{cout << '-';x = -x;}string s = "";// 将数字转换为字符串,取模得到最低位,累加字符while (x > 0) {s += (x % 10 + '0'); // 取个位数字并转成字符x /= 10; // 去掉个位数字,向高位进位}// 因为是从低位向高位依次加入字符,字符串是反向的,需反转reverse(s.begin(), s.end());cout << s; // 输出字符串
}int main()
{ll n;cin >> n; // 输入顶点个数(多边形点数)vector<ll> w(n + 1, 0); // 权值数组,1-based 索引,w[i] 为第 i 个顶点的权值for (ll i = 1; i <= n; i++){cin >> w[i];}// 定义一个很大的数 N 作为无穷大(INF),用来初始化 DP 表// N = 2^(121),非常大,远大于可能出现的最大代价,防止溢出lll N = 2;for (ll i = 0; i < 120; i++){N *= 2;}// 初始化 DP 数组,dp[i][j] 表示区间 [i,j] 的最小剖分代价// 一开始赋值为无穷大 N,表示暂时不可达或未计算vector<vector<lll>> dp(n + 1, vector<lll>(n + 1, N));// 区间长度为 1 或 2 的子区间不构成三角形,代价为 0// 所以这些区间 dp 值初始化为 0for (ll len = 1; len <= 2; len++){for (ll i = 1; i + len - 1 <= n; i++){ll j = i + len - 1;dp[i][j] = 0;}}// 区间 DP 主要部分:从长度 3 到 n 的区间逐步计算最小代价for (ll len = 3; len <= n; len++){for (ll i = 1; i + len - 1 <= n; i++){ll j = i + len - 1;// 尝试所有可能的中间分割点 k,将区间 [i,j] 分成 [i,k] 和 [k,j]for (ll k = i + 1; k < j; k++){// 代价由三部分组成:// 左子区间最优代价 dp[i][k]// 右子区间最优代价 dp[k][j]// 当前剖分三角形代价 w[i] * w[k] * w[j]lll cost = dp[i][k] + dp[k][j] + (lll)w[i] * w[k] * w[j];// 取所有分割点中的最小代价dp[i][j] = min(dp[i][j], cost);}}}// 打印最终结果,dp[1][n] 即整个多边形的最小剖分代价print128(dp[1][n]);cout << "\n";return 0;
}
————————
详细题解,后续更新