AcWing1069.凸多边形的划分(区间DP)题解

凸多边形的划分
题目传送门
题目描述

给定一个具有 N 个顶点的凸多边形,将顶点从 1 至 N 标号,每个顶点的权值都是一个正整数。

将这个凸多边形划分成 N−2 个互不相交的三角形,对于每个三角形,其三个顶点的权值相乘都可得到一个权值乘积,试求所有三角形的顶点权值乘积之和至少为多少。

输入格式

第一行包含整数 N,表示顶点数量。

第二行包含 N 个整数,依次为顶点 1 至顶点 N 的权值。

输出格式

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

数据范围

N≤50
数据保证所有顶点的权值都小于10^9

输入样例:

5
121 122 123 245 231

输出样例:

12214884

题解:

区间DP:

DP[ i ] [ j ]表示当底边为i ~ j时, 权值的最小值,枚举顶点k,因为不能相交,所以k属于[i + 1, j - 1],

这样我们就可以把图形划分为3个区间(i ~ k - 1), (k + 1, r) 和(i, j, k)这个三角形

所以d[ l ] [ r ] = min(d[ l ] [ r ], d[ l ] [ k - 1] + d[k + 1] [ r ] + w[l] * w[k] * w[r]

这道题要用高精度

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 55, M = 35;
int n, a[N];
ll f[N][N][M];
ll c[M];
void add(ll a[], ll b[])  //高精度加法
{
    ll t = 0;
    memset(c, 0, sizeof c);
    for(int i = 0; i < M; i++){
        t += a[i] + b[i];
        c[i] = t % 10;
        t /= 10;
    }
    memcpy(a, c, sizeof c);
}
void mul(ll a[], ll b){  //高精度乘法
    memset(c, 0, sizeof c);
    ll t = 0;
    for(int i = 0; i < M; i++){
        t += a[i] * b;
        c[i] = t % 10;
        t /= 10;
    }
    memcpy(a, c, sizeof c);
}
int cmp(ll a[], ll b[])  //高精度比较
{
    for(int i = M - 1; i >= 0; i--){
        if(a[i] > b[i])return 1;
        else if(a[i] < b[i])return -1;
    }
    return 0;
}
void print(ll a[])  //高精度输出
{
    int k = M - 1;
    while(k > 0 && a[k] == 0)k--;
    while(k >= 0){
        cout << a[k];
        k--;
    }
    cout << endl;
}
int main()
{
    
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    ll temp[N];
    for(int len = 3; len <= n; len++){  //枚举长度
        for(int l = 1; l + len - 1 <= n; l++){  //枚举区间
            int r = l + len - 1;
            f[l][r][M - 1] = 1; //先初始化为最大值,让最高位等于1
            for(int k = l + 1; k < r; k++){
                memset(temp, 0, sizeof temp);
                temp[0] = a[l];
                mul(temp, a[k]);
                mul(temp, a[r]);
                add(temp, f[l][k]);
                add(temp, f[k][r]);
                if(cmp(f[l][r], temp) > 0){
                    memcpy(f[l][r], temp, sizeof temp);
                }
            }
        }
    }
    print(f[1][n]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值