caioj 1106 树形动态规划(TreeDP)1:加分二叉树

解这道题的前提是非常熟悉中序遍历的方式
我就是因为不熟悉而没有做出来
中序遍历是5 7 1 2 10的话,如果1是根节点
那么5 7 1就是1的左子树,2, 10就是右子树
这就有点中链式dp的味道了,实际解法也是中链式dp的解法
设f[i][j]为中序遍历从i到j的最大价值
f[l][r] = f[l][mid-1] * f[mid+1][r] + d[mid]
从小规模推到大规模
dp过程中记录根节点以求前序遍历。

#include<cstdio>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;

const int MAXN = 30;
int d[MAXN], f[MAXN][MAXN], root[MAXN][MAXN], n;

void print(int l, int r)
{
	if(l <= r)
	{
		printf("%d ", root[l][r]);
		print(l, root[l][r] - 1);
		print(root[l][r] + 1, r);
	}
}

int main()
{
	scanf("%d", &n);
	REP(i, 0, n + 1)
		REP(j, 0, n + 1)
			f[i][j] = 1;
	REP(i, 1, n + 1) 
	{
		scanf("%d", &d[i]);
		f[i][i] = d[i];
		root[i][i] = i;
	}
	
	REP(k, 2, n + 1)
		for(int l = 1; l + k - 1 <= n; l++)
		{
			int r = l + k - 1;
			REP(mid, l, r + 1)
				if(f[l][r] < f[l][mid-1] * f[mid+1][r] + d[mid])
				{
					f[l][r] = f[l][mid-1] * f[mid+1][r] + d[mid];
					root[l][r] = mid;
				}
		}
	
	printf("%d\n", f[1][n]);
	print(1, n);
	
	return 0;
}

 

posted @ 2018-08-31 10:37  Sugewud  阅读(161)  评论(0编辑  收藏  举报