P1040 加分二叉树

题意:

给定一个中序遍历为1,2,3,…,n的二叉树 每个结点有一个权值 定义二叉树的加分规则为: 左子树的加分× 右子树的加分+根的分数 若某个树缺少左子树或右子树,规定缺少的子树加分为1。 构造符合条件的二叉树 该树加分最大 输出其前序遍历序列

想法:

中序遍历的方法是 左子树 根 右子树

因此二叉树左孩子遍历序列一定在根结点的左边,右孩子遍历序列一定在根结点的右边! 因此,假设二叉树的根结点为k,那么中序遍历为1,2,…,n的遍历序列,左孩子序列为1,2,…,k-1,右孩子序列为k+1,k+2,…,n

f(i,j)中序遍历为i,i+1,…,j的二叉树的最大加分,则有: f(i,j)=max{f[i,k-1]*f[k+1,j] +d[k]} 显然 f(i,i)=d[i] 答案为f(1,n)

枚举根节点就好了

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 100;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

LL f[maxn][maxn];
int root[maxn][maxn];
bool flag = true;

inline LL find(int l,int r) {
   if (l > r)
       return 1;
   LL now;
   if (f[l][r] == -1) {
       for (int k = l;k <= r;k++) {
          now = find(l,k-1)*find(k+1,r) + f[k][k];
          if (now > f[l][r]) {
              f[l][r] = now;
              root[l][r] = k;
          }
       }
   }
   return f[l][r];
}

inline void pre(int l,int r) {
    if (l > r)
        return;
    if (flag) {
        flag = false;
    }
    else
        cout << " ";
    cout << root[l][r];
    pre(l,root[l][r]-1);
    pre(root[l][r]+1,r);
}

int main() {
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= n;j++)
            f[i][j] = -1;
    }
    for (int i = 1;i <= n;i++) {
        cin >> f[i][i];
        root[i][i] = i;
    }
    cout << find(1,n) << endl;
    flag = true;
    pre(1,n);
    return 0;
}
原文地址:https://www.cnblogs.com/-Ackerman/p/12345784.html