输入输出样例
输入 #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;
}