加分二叉树

加分二叉树
数据很小, 肯定考率爆搜

题目连接

设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数
若某个子树为主,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。 试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。
要求输出:
(1)tree的最高加分
(2)tree的前序遍历

中序遍历时1 , 2 , 3 , 4 … n , 说明随便一个点都可以作为根节点,左边就是左子树,右边就是右子树,有这么个性质我们就可以枚举一下根节点。算贡献的话题目已经给出公式了,可以采取记忆化搜索的方式来爆搜

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std ;
typedef long long ll ;
#define ios ios::sync_with_stdio(false),  cin.tie(0) ,cout.tie(0)
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
int in()
{
  int x = 0 , f = 1 ;
  char ch = getchar() ;
  while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
  while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
  return x * f ;
}
int dp[40][40] , n , path[40][40] , a[N] ; 
// path[l][r] 表示l和r的最近公共祖先 , 也就相当于最近的一个根节点

int dfs(int l , int r) // 求l 到 r组成一个数的最大加分数
{
// 如果当前l到r已经被算过了,直接返回
  if(dp[l][r] != 0) return dp[l][r] ; 
  // 这个地方是因为l 大于 r了, 这个时候返回1还要和他的上一级(谁调用的这个区间)相乘,所以不能返回0
  if(l > r) return 1 ;
  // 每一个叶子子节点的公共祖先就是他自己, 最大加分数也是他自己
  if(l == r) {
    path[l][r] = l ;
    return a[l] ;
  }
  int &ans = dp[l][r] = 0 ;
  for(int i = l ;i <= r ;i ++ )
   {
     //枚举当前l到r区间的根节点 , 那么左区间就是l ~ (i - 1) , 右区间就是(i + 1) ~ r , 然后加上当前a[i]
     int temp = dfs(l , i - 1) * dfs(i + 1 , r) + a[i] ;
     // 当前i作为根节点更优
     if(temp > ans) ans = temp , path[l][r] = i ;
   }
  return ans ;
}
void get(int l , int r)
{
  if(l > r) return ;
  cout << path[l][r] << " " ;
  get(l , path[l][r] - 1) , get(path[l][r] + 1 , r) ;
}
int main()
{
  ios ;
  n = in() ;
  for(int i = 1; i <= n ;i ++ ) a[i] = in() ;
  cout << dfs(1 , n) << endl ;
  get(1 , n) ;
  return 0 ;
}
/*
*/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值