树形动态规划
•给定一个中序遍历为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
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);
}
}