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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章