PS:如果读过题了可以跳过题目描述直接到题解部分
提交链接:洛谷 T282062 凸多边形的划分
题目
题目描述
给定一个具有 N 个顶点的凸多边形,将顶点从 1 至 N 标号,每个顶点的权值 都是一个正整数。将这个凸多边形划分成 N-2 个互不相交的三角形,试求这些 三角形顶点的权值乘积和至少为多少
输入格式
输入第一行为顶点数 N 第二行依次为顶点 1 至顶点 N 的权值
输出格式
输出仅一行,为这些三角形顶点的权值乘积和的最小值。
样例 #1
样例输入 #1
5
121 122 123 245 231
样例输出 #1
12214884
提示
对于 100% 的数据,有 N≤50,每个点权值小于 1 0 9 10^9 109。
题解
区间DP
循环区间长度和起点,求出终点,再循环中间经过的点,求最小值就好了。
其实吧,整个就比较像Dijkstra的最短路。
高精
它每个是 1 0 9 10^9 109 ,三个相乘就是 1 0 27 10^{27} 1027 ,所以一定要用高精!!!
代码实现
//洛谷 T282062 凸多边形的划分
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
int num[60];
char x[30];
struct node{
int v[30];
int l;
node(){
memset(v,0,sizeof(v));
l=29;
}
}a[60],f[60][60],ans;
void in(int &x){
int nt;
x=0;
while(!isdigit(nt=getchar()));
x=nt^'0';
while(isdigit(nt=getchar())){
x=(x<<3)+(x<<1)+(nt^'0');
}
}
bool operator>(node a,node b){
if(a.l>b.l){
return 1;
}
else if(a.l<b.l){
return 0;
}
for(int i=a.l-1;i>=0;--i){
if(a.v[i]>b.v[i]){
return 1;
}
else if(a.v[i]<b.v[i]){
return 0;
}
}
return 0;
}
node operator+(node a,node b){
node c;
for(int i=0;i<=max(a.l,b.l);i++){
c.v[i]+=a.v[i]+b.v[i];
c.v[i+1]+=c.v[i]/10;
c.v[i]=c.v[i]%10;
}
c.l=max(a.l,b.l);
while(c.v[c.l]==0&&c.l>0){
--c.l;
}
++c.l;
return c;
}
node operator*(node a,node b){
node c;
for(int i=0;i<a.l;++i){
for(int j=0;j<b.l;++j){
c.v[i+j]+=a.v[i]*b.v[j];
c.v[i+j+1]+=c.v[i+j]/10;
c.v[i+j]%=10;
}
}
c.l=a.l+b.l;
while(c.v[c.l]==0&&c.l>0){
--c.l;
}
++c.l;
return c;
}
int main(){
register int i,j,k,l;
in(n);
for(i=1;i<=n;++i){
scanf("%s",&x);
a[i].l=strlen(x);
for(j=0;j<a[i].l;++j){
a[i].v[a[i].l-j-1]=x[j]^'0';
}
}
for(l=2;l<=n-1;++l){
for(i=1;i<=n-l;++i){
j=i+l;
for(k=i+1;k<j;++k){
ans=f[i][k]+f[k][j]+a[i]*a[j]*a[k];
if(f[i][j]>ans){
f[i][j]=ans;
}
}
}
}
while(f[1][n].v[f[1][n].l]==0&&f[1][n].l>0){
--f[1][n].l;
}
for(i=f[1][n].l;i>=0;--i){
printf("%d",f[1][n].v[i]);
}
return 0;
}