1571:【例 3】凸多边形的划分——典型的区间dp问题,值得一看

1571:【例 3】凸多边形的划分

【题目描述】

给定一个具有 N N N 个顶点的凸多边形,将顶点从1至 N N N标号,每个顶点的权值都是一个正整数。将这个凸多边形划分成 N − 2 N−2 N2 个互不相交的三角形,试求这些三角形顶点的权值乘积和至少为多少。

【输入】

输入第一行为顶点数 N N N
第二行依次为顶点 1 至顶点 N N N 的权值。

【输出】

输出仅一行,为这些三角形顶点的权值乘积和的最小值。

【输入样例】

5
121 122 123 245 231

【输出样例】

12214884

【提示】

数据范围与提示:

对于 100% 的数据,有 N ≤ 50 N≤50 N50,每个点权值小于 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;
}





  • 29
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值