樹上dp

枚舉從 l -> r 中的點做頂點下的左右子樹的分數, dp找每次最大的分數

dfs(l, k-1)*dfs(k+1, r) + f[k][k]; // k 為 根節點時, l,k-1 為左子樹  k+1,r 右子樹
#include <bits/stdc++.h>
using namespace std;
#define _for(i,a,b) for(int i = (a); i < (b); i++)
#define _rep(i,a,b) for(int i = (a); i <= (b); i++)
#define ll long long
int n, f[40][40], root[40][40];
bool flag = true;
int dfs(int l, int r){
    int sum = 0;
    if(l > r) return 1;// 空子樹
    if(!f[l][r]){
        _rep(k,l,r)
        {
            sum = dfs(l, k-1)*dfs(k+1, r) + f[k][k];//狀態轉移
            if(sum > f[l][r])
                f[l][r] = sum, root[l][r] = k;
        }
    }
    return f[l][r];
}
void printfront(int l, int r){
    if(l > r) return ;
    if(flag) flag = false;
    else cout << " ";
    cout << root[l][r];
    printfront(l, root[l][r]-1);// 根 左子樹  右子樹
    printfront(root[l][r]+1, r);
}
void solve(){
    cin >> n;
    memset(f, 0, sizeof(f));
    _rep(i,1,n) cin >> f[i][i], root[i][i] = i;
    cout << dfs(1, n) << endl;
    printfront(1, n);
}

int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    //freopen("output.txt", "w", stdout);
    solve();
    return 0;
}
12-28 15:09