1571:【例 3】凸多边形的划分
【题目描述】
给定一个具有 N N N 个顶点的凸多边形,将顶点从1至 N N N标号,每个顶点的权值都是一个正整数。将这个凸多边形划分成 N − 2 N−2 N−2 个互不相交的三角形,试求这些三角形顶点的权值乘积和至少为多少。
【输入】
输入第一行为顶点数
N
N
N
第二行依次为顶点 1 至顶点
N
N
N 的权值。
【输出】
输出仅一行,为这些三角形顶点的权值乘积和的最小值。
【输入样例】
5
121 122 123 245 231
【输出样例】
12214884
【提示】
数据范围与提示:
对于 100% 的数据,有 N ≤ 50 N≤50 N≤50,每个点权值小于 1 0 9 10^9 109
状态:dp[i][j]表示点i到点j划分成(j-i-1)个三角形的最优解。
还是考虑最后一次划分,一次划分只能把一个图形变成两个图形,最后一次划分的断点k可以是中间任意一个满足条件的点。f[i][k]表示区域S1的最优解,f[k][j]表示区域S2的最优解,但是还有区域S3没有包含,S3就是一个简单三角形,权值就为三个点之积。可以得到状态转移方程:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
k
]
+
d
p
[
k
]
[
j
]
+
m
u
l
(
i
,
j
,
k
)
)
dp[i][j]=min(dp[i][k]+dp[k][j]+mul(i,j,k))
dp[i][j]=min(dp[i][k]+dp[k][j]+mul(i,j,k))
但是我们要注意一下数据范围,不难发现是要开高精度的,但是作者比较懒,所以就使用了__int128
,注:__int128
需要使用快读快写
#include<bits/stdc++.h>
using namespace std;
inline __int128 read(){
__int128 x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-')f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline void write(__int128 x){
if (x<0)putchar('-'),x=-x;
if (x>9)write(x/10);
putchar(x%10+'0');
}
__int128 a[150];
__int128 dp[150][150];
int main(){
int n;
cin>>n;
for (int i=1;i<=n;i++){
a[i]=read();
}
for (int len=3;len<=n;len++){
for (int l=1;l+len-1<=n;l++){
int r=l+len-1;
dp[l][r]=dp[l][l+1]+dp[l+1][r]+a[l]*a[l]*a[l+1]*a[r];
for (int i=l+1;i<r;i++){
dp[l][r]=min(dp[l][r],dp[l][i]+dp[i][r]+a[l]*a[i]*a[r]);
}
}
}
write(dp[1][n]);
return 0;
}