加分二叉树-----------------------------区间dp

加分二叉树-----------------------------区间dp_第1张图片

加分二叉树-----------------------------区间dp_第2张图片
解析:
根据二叉树性质中序遍历: 左(根)右
题目要求中序遍历是1~n
那说明一个性质 根的左子树节点编号都小于根
根的右子树节点编号都大于根。

根据这个性质我们可以枚举根
那么递推方程: f[l][k-1] * f[k+1][r] + a[k]
怎么输出前序遍历呢??我们另开一个数组记录当状态转移时根是哪个

初始化: f[i][i]=a[i]
其他的都 f[i][j]=1 因为题目要求某子树为空,加分为1(除叶子节点)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10000;
ll f[100][100];
 int pre[100][100],n;
ll a[N];
 void dfs(int l,int r)
 {
 	if(l>r) return;
 	int k=pre[l][r];
 	cout<<k<<" ";
 	dfs(l,k-1);dfs(k+1,r);
 }
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=0;i<=n+1;i++)
		for(int j=0;j<=n+1;j++)
			f[i][j]=1;	
	for(int i=1;i<=n;i++) f[i][i]=a[i],pre[i][i]=i;
	for(int len=2;len<=n;len++)
		for(int i=1;i+len-1<=n;i++)
		{
			int j=i+len-1;
			f[i][j]=0;
			for(int k=i;k<=j;k++)
			{
				int u=f[i][k-1]*f[k+1][j]+a[k];
				if(f[i][j]<u)
				{
					f[i][j]=u;
					pre[i][j]=k;
				}
			}
		}
		cout<<f[1][n]<<endl;
		dfs(1,n);
		return 0;
 } 

你可能感兴趣的:(DP,思维)