动态规划之树形动态规划

树形动态规划

 •给定一个中序遍历为1,2,3,,n的二叉树

每个结点有一个权值

定义二叉树的加分规则为:

左子树的加分×右子树的加分+根的分数

若某个树缺少左子树或右子树,规定缺少的子树加分为1

构造符合条件的二叉树

该树加分最大

输出其前序遍历序列

定义dp[i][j] 为中序遍历为i-->j的二叉树的最大加分

那么dp[i][j] = max{dp[i][k-1] * dp[k+1][j] + a[k];   i<=k<=j}

 其实就相当于区间dp,只不过是在树上而已

动态规划: 

  问题可以分解成若干相互联系的阶段,在每一个阶段都要做出决策,全部过程的决策是一个决策序列。要使整个活动的总体效果达到最优的问题,称为多阶段决策问题。动态规划就是解决多阶段决策最优化问题的一种思想方法。

阶段:

  将所给问题的过程,按时间或空间(树归中是空间,即层数)特征分解成若干相互联系的阶段,以便按次序去求每阶段的解。

状态:

  各阶段开始时的客观条件叫做状态。

决策:

  当各段的状态取定以后,就可以做出不同的决定,从而确定下一阶段的状态,这种决定称为决策。 (即孩子节点和父亲节点的关系)

 

策略:

  由开始到终点的全过程中,由每段决策组成的决策序列称为全过程策略,简称策略。

状态转移方程:

  前一阶段的终点就是后一阶段的起点,前一阶段的决策选择导出了后一阶段的状态,这种关系描述了由k阶段到k+1阶段(在树中是孩子节点和父亲节点)状态的演变规律,称为状态转移方程。

 

目标函数与最优化概念:

  目标函数是衡量多阶段决策过程优劣的准则。最优化概念是在一定条件下找到一个途径,经过按题目具体性质所确定的运算以后,使全过程的总效益达到最优。

树的特点与性质:

1、 有n个点,n-1条边的无向图,任意两顶点间可达

2、 无向图中任意两个点间有且只有一条路

3、 一个点至多有一个前趋,但可以有多个后继

4、 无向图中没有环;

输入样例:


5 7 1 2 10

#include <stdio.h>
#include <string.h>

int a[30];
int dp[30][30];//dp[i][j] 表示某子树的中序遍历为i-->j    那么dp[i][i]则表示i为叶子结点
int root[30][30];

void print(int i, int j)
{
    if(i>j)return;
    if(root[i][j]==-1) return;
    printf("%d ",root[i][j]+1);
    print(i,root[i][j]-1);
    print(root[i][j]+1,j);
}
int main()
{
    int n,i,j,k,t;
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,-1,sizeof(dp));
        memset(root,-1,sizeof(root));
        for(i=0; i<n; ++i)
        {
            scanf("%d",&a[i]);
            dp[i][i] = a[i];
            root[i][i] = i;
        }
        for(t=1; t<n; ++t)//枚举长度
            for(i=0; i<n-t; ++i)//枚举起点
            {
                j = t + i;//区间总长度
                for(k=i+1; k<j; ++k)
                    if(dp[i][j] < (dp[i][k-1]*dp[k+1][j]+a[k]))
                    {
                        dp[i][j] = dp[i][k-1]*dp[k+1][j]+a[k];
                        root[i][j] = k;
                    }
                if(dp[i][j] < dp[i][j-1] + a[j])
                {
                    dp[i][j] = dp[i][j-1] + a[j];
                    root[i][j] = j;
                }
                if(dp[i][j] < dp[i+1][j] + a[i])
                {
                    dp[i][j] = dp[i+1][j] + a[i];
                    root[i][j] = i;
                }
            }
        printf("%d\n",dp[0][n-1]);
        print(0,n-1);
    }
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值