1069. 凸多边形的划分
题目链接
1069. 凸多边形的划分
给定一个具有 \(N\) 个顶点的凸多边形,将顶点从 \(1\) 至 \(N\) 标号,每个顶点的权值都是一个正整数。
将这个凸多边形划分成 \(N?2\) 个互不相交的三角形,对于每个三角形,其三个顶点的权值相乘都可得到一个权值乘积,试求所有三角形的顶点权值乘积之和至少为多少。
输入格式
第一行包含整数 \(N\),表示顶点数量。
第二行包含 \(N\) 个整数,依次为顶点 \(1\) 至顶点 \(N\) 的权值。
输出格式
输出仅一行,为所有三角形的顶点权值乘积之和的最小值。
数据范围
\(N≤50,\)
数据保证所有顶点的权值都小于\(10^9\)
输入样例:
5
121 122 123 245 231
输出样例:
12214884
解题思路
区间dp
-
状态表示:\(f[l][r]\) 表示区间 \([l,r]\) 内构成的凸多边形的最少权值之和
-
状态计算:\(f[l][r]=min(f[l][r],f[l][k]+f[k][r]+a[l]*a[r]*a[k])\),其中 \(k\) 为区间 \([l,r]\) 上的点
分析:枚举区间端点 \(l\) 和 \(r\) 和区间内的哪个点形成一个三角形
注意:这里不用破环成链,因为区间 \([1,n]\) 就代表了整个凸多边形,\(1\) 和 \(n\) 两个端点总是要和剩余一点组成三角形,这样的状态计算任何一种三角形都考虑进去了
另外,这里会爆long long
,但不超过__int128
范围
- 时间复杂度:\(O(n^3)\)
代码
// Problem: 凸多边形的划分
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/1071/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
template
void print(T x) {
if (x < 0) putchar('-'), x = -x;
if (x < 10) putchar(x + 48);
else print(x / 10), putchar(x % 10 + 48);
}
const int N=110;
int n;
__int128 f[N][N],a[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
read(a[i]);
for(int i=1;i<=n;i++)f[i][i+2]=a[i]*a[i+1]*a[i+2];
for(int len=4;len<=n;len++)
for(int l=1;l+len-1<=n;l++)
{
__int128 r=l+len-1;
f[l][r]=1e30;
for(int k=l+1;k<=r-1;k++)
f[l][r]=min(f[l][r],f[l][k]+f[k][r]+a[l]*a[r]*a[k]);
}
__int128 res=1e30;
print(f[1][n]);
return 0;
}