AcWing 1069 凸多边形的划分

题目描述:

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

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

输入格式

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

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

输出格式

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

数据范围

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

输入样例:

5
121 122 123 245 231

输出样例:

12214884

分析:

首先需要考虑如何将本题划分为若干个相似的子问题。

如上图所示,一个编号为1到6的六边形,我们考虑划分时边16会被哪个三角形选中,顶点1,6构成的三角形可以是126,136,146,156。比如随便选取其中的一个三角形146,原图形就被划分为了三部分,最简单的蓝色三角形146,以及蓝色三角形上面的图形和下面的图形,由于划分的三角形不能交叉,所以不会存在像125这样会与146交叉的三角形,也就是说,这三部分,任意一部分都是一个独立的子问题。我们考虑了由顶点1和N构成的三角形后,剩下的两部分都是与原问题相同但是规模小于原问题的独立子问题,这就类似于石子合并问题,找到到中间蓝色三角形的代价,然后加上上下部分代价就是原问题的代价了。即f[i][j]表示顶点编号i到j多边形中所有三角形权值乘积之和的最小值,状态转移方程为f[i][j] = min(f[i][j],f[i][k]+f[k][j] + w[i]*w[j]*w[k])。本来是道简单的区间DP问题,但是数据范围较大,需要用高精度实现加法和乘法运算。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define vi vector<int>
using namespace std;
typedef long long ll;
const int N = 55;
int a[N];
vi f[N][N];
void add(vi& x,vi& y,vi& z){
    if(x.size() < y.size()) add(y,x,z);
    else{
       int t = 0;
       for(int i = 0;i < x.size();i++){
            t += x[i];
            if(i < y.size())    t += y[i];
            z.push_back(t % 10);
            t /= 10;
        } 
        if(t)   z.push_back(t);
    }
    
}
void mul(vi& x,ll y,vi& z){
    ll t = 0;
    for(int i = 0;i < x.size() || t;i++){
        if(i < x.size())    t += x[i] * y;
        z.push_back(t % 10);
        t /= 10;
    }
}
bool cmp(vi& x,vi& y){
    if(x.size() != y.size())    return x.size() < y.size();
    int i = x.size() - 1;
    while(i && x[i] == y[i])    i--;    
    return x[i] < y[i];
}
int main(){
    int n;
    cin>>n;
    for(int i = 1;i <= n;i++)   cin>>a[i];
    for(int len = 3;len <= n;len++){
        for(int l = 1;l+len-1<= n;l++){
            int r = l + len -1;
            for(int k = l + 1;k < r;k++){
                vi res,s,t(1,a[l]);
                mul(t,a[r],s),mul(s,a[k],res);
                s.clear(),t.clear();
                add(f[l][k],f[k][r],s),add(s,res,t);
                if(f[l][r].empty() || cmp(t,f[l][r])) f[l][r] = t;
            }
        }
    }
    for(int i = f[1][n].size() - 1;i >= 0;i--)  cout<<f[1][n][i];
    return 0;
}
发布了311 篇原创文章 · 获赞 31 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_30277239/article/details/104379856