DFS(5)P1040 加分二叉树——树形DP与记忆化搜索

在这里插入图片描述

输入输出样例
输入 #1复制
5
5 7 1 2 10
输出 #1复制
145
3 1 2 4 5

总结目录

1 本题的DFS搜索思路
2 如何使用记忆化搜索来减少时间

1 本题的DFS搜索思路

在本题中,我们的求值过程是使用左子树的分数,右子树的分数还有根节点的分数。这里很神奇的是我们并没有使用树的结构。而是直接使用了一组序列就足够表示树了。 对于这一题,如果是人来做的话,大概就会不断的枚举,比如以第一个点为根节点,以第二个点为根节点,然后依此类推。那么DFS的本质也是类似的。在这里,先枚举以第一个为根节点,然后其余为右子树;再枚举以第二个为根节点,然后左边为左子树,右边为右子树 (因为题目给出的是中序遍历的节点顺序)。 我们定义DFS(l,r)得到的是[l,r]区间内的树的分数的最大值。那么容易定义一个maxsum[l][r]来进行记录,并且可以得到root[l][r]为[l,r]区间内的根节点的序号。

2 如何使用记忆化搜索来减少时间

在本题中,DFS的时候我们通过判断

if(maxsum[l][r]!=0){
return maxsum[l][r];
}

来减少了搜索的时间。但是为什么这里可以直接返回?为什么不需要担心这个值被更新了?
因为这里的这个值的同一个阶段的计算方式都是一样的,所以基本不存在重复计算同一阶段而产生更新的情况。这里更加像是一种枚举。

代码

#include<iostream>
#define maxsize 100
using namespace std;
int tree[maxsize];
int root[maxsize][maxsize];
int maxsum[maxsize][maxsize];
int n;

int dfs(int l, int r) {
	//求出[l,r]区间内的最大和
	if (l == r) {
		root[l][r] = l;
		return tree[l];
	}
	if (l > r) {
		return 1;
	}
	if (maxsum[l][r]) {
		//思考:为什么这里可以使用记忆化搜索?为什么不去更新这个值,难道这个值就是最大的吗?
		//这里的搜索类似于枚举,每一次枚举在相同区间内的计算过程是完全一样的,因此在相同区间内不存在更新,因此完全可以使用记忆化搜索。
		return maxsum[l][r];
	}

	for (int i = l; i <= r; i++) {
		int temp = dfs(l, i - 1)*dfs(i + 1, r) + tree[i];
		if (temp > maxsum[l][r]) {
			maxsum[l][r] = temp;
			root[l][r] = i;
		}
	}
	return maxsum[l][r];
}

void TreeTransver(int l,int r) {
	//前序遍历输出,先输出根节点
	if (l > r)return;
	cout << root[l][r] << " ";
	TreeTransver(l, root[l][r] - 1);
	TreeTransver(root[l][r]+1,r);
}

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> tree[i];
	}

	cout<<dfs(1, n)<<endl;
	TreeTransver(1, n);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值