P1040 加分二叉树(记忆化搜索 或 树型dp)

题目链接:https://www.luogu.com.cn/problem/P1040

思路一:记忆化搜索

要寻找区间之间的关系,寻找谁是谁的子树,谁是根节点。

dp(l,r)表示区间l,r区间所能凑出的最大值是多少,然后不停的递归下去,就能找到所有的根节点,在确定最大值的

同时求出这棵树。

(可以考虑逆向的做法,因为通常都是给出树让你进行遍历或者求树上的最值,但是如果树不确定,我们可以在搜索最大值的时候建树就好了)。

代码一:

#include <bits/stdc++.h>
using namespace std;
const int N = 220;
typedef long long ll;
ll dp[N][N] = {0};
int n,tot = 0,b[N],path[N][N] = {0};
ll dfs(int l,int r)
{
    if(l>r) return 1;
    if(dp[l][r] > 0) return dp[l][r];
    for(int i=l;i<=r;i++){
        ll tp = dfs(l,i-1)*dfs(i+1,r) + dp[i][i];
        if(tp > dp[l][r]){ //求出最大值
            dp[l][r] = tp; path[l][r] = i; //路径记录
        }
    }
    return dp[l][r];
}
void fd(int l,int r)
{
    if(l>r) return ;
    if(l == r) { b[++tot] = l; return; }
    b[++tot] = path[l][r];
    fd(l,path[l][r]-1);
    fd(path[l][r]+1,r);
}
int main(void)
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&dp[i][i]);
    printf("%lld\n",dfs(1,n));
    fd(1,n);
    for(int i=1;i<=tot;i++)
    {
        if(i>1) printf(" ");printf("%d",b[i]);
    }
    return 0;
}

思路一:
就是区间dp,注意一定要判断没有左(右)子树的情况。

代码二:

#include <bits/stdc++.h>
using namespace std;
const int N = 220;
typedef long long ll;
ll dp[N][N] = {0};
int path[N][N] = {0},n,b[N],tot = 0;
void dfs(int l,int r)
{
    if(l > r) return ;
    if(l == r) { b[++tot] = l; return ; }
    b[++tot] = path[l][r];
    dfs(l,path[l][r] - 1);
    dfs(path[l][r] + 1,r);
}
int main(void)
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&dp[i][i]),dp[i][i-1] = 1ll,path[i][i] = i;
    for(int i=2;i<=n;i++) //枚举区间长度
    {
        for(int l=1;l+i-1<=n;l++) //枚举左区间
        {
            int r = l+i-1;
            dp[l][r] = dp[l][l] + dp[l+1][r]; //注意,这里要初始化,因为可能存在没有左子树的情况。
            path[l][r] = l;
            for(int j=l+1;j<=r;j++) //可以求出只有右子树的情况
            {
                if(dp[l][j-1]*dp[j+1][r] + dp[j][j] > dp[l][r])
                {
                    dp[l][r] = dp[l][j-1]*dp[j+1][r] + dp[j][j];
                    path[l][r] = j;
                }
            }
        }
    }
    dfs(1,n);
    printf("%lld\n",dp[1][n]);
    for(int i=1;i<=n;i++)
    {
        if(i>1) printf(" ");
        printf("%d",b[i]);
    }
    return 0;
}
发布了438 篇原创文章 · 获赞 16 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41829060/article/details/103773680