【动态规划】[NOIP2003]加分二叉树

来源:互联网 发布:mysql连接工具 编辑:程序博客网 时间:2024/06/09 11:26

题目

感觉这个题挺难的啊 毕竟dp很弱
一个比较经典的树形dp
我们用f[i][j]表示区间i~j的最大加分 dp[i][j]表示区间i~j的最大加分时的根节点是什么 所以初始化f[i][i] = a[i] dp[i][i] = i
然后就是循环枚举区间 然后在每个区间中在枚举根节点 如果发现当前区间的左子树的加分×右子树的加分 + 根的分数大于当前的f[i][j]就更新
最后还要输出一个前序遍历 也就是头左右 深搜一下即可

代码如下

#include<iostream>#include<cstdio>#include<cctype>    using namespace std;    #define in = read()    typedef long long ll;    typedef unsigned int ui;    const ll size = 100 + 1;        int n , l , r;        int a[size] , f[size][size] , dp[size][size];inline ll read(){        ll num = 0 , f = 1;     char ch = getchar();        while(!isdigit(ch)){                if(ch == '-')   f = -1;                ch = getchar();        }        while(isdigit(ch)){                num = num*10 + ch - '0';                ch = getchar();        }        return num*f;}void dfs(int x , int y){        printf("%d " , dp[x][y]);        if(dp[x][y] > x)    dfs(x , dp[x][y] - 1);        if(dp[x][y] < y)    dfs(dp[x][y] + 1 , y);}int main(){        n in;        for(register int i=1;i<=n;i++){                a[i] in;                f[i][i] = a[i];                dp[i][i] = i;        }        int j;        for(register int u=2;u<=n;u++)                for(register int i=1;i+u-1<=n;i++){                        j = i + u - 1;                        for(register int k=i;k<=j;k++){                                l = f[i][k - 1];    r = f[k + 1][j];                                if(k == i && k != j)    l = 1;                                if(k == j && k != i)    r = 1;                                if(f[i][j] < l*r + f[k][k]){                                        dp[i][j] = k;                                        f[i][j] = l*r + f[k][k];                                }                        }                }        printf("%d\n" , f[1][n]);        dfs(1 , n);        return 0;}//COYG
原创粉丝点击