1.通常的动态规划都是线性的,或者说是在有向无环图上进行的。而树形dp就是在树的基础上进行的dp
2.树形dp通常有两种方向,一种是自下而上,另一种是自上而下。具体利用方法根据实际要求来
叶——根,在回溯的时候从叶子节点往上更新信息
根——叶,往往是在叶——根dfs一遍以后(相当于预处理),再重新往下获取,得到的最终答案。
3.和普通dp一样,树形dp的重点在于找状态转移方程。
一.入门题
上司的舞会上司的舞会
题目大意:
如题目所言,就是自己的上司参加的话,自己就不能参加。每个节点定义一个价值,子节点和父亲节点不能同时选取。求能够选取的最大价值
题目分析:令f【u】【0】表示不选取u节点,u子树所能得到的最大价值;f【u】【1】表示选取了u节点,u子树能得到的最大价值。
在回溯的过程中通过子节点向上更新信息
设i号节点的价值为a【i】,<u,v>是一条有向边
f【u】【0】=max(f【v】【0】,f【v】【1】)
f【u】【1】=a【u】+f【v】【0】u取了,v肯定不取
void dfs(int x)
{
int l=tu[x].size();
for(int i=0;i<l;i++)
{
int t=tu[x][i];
dfs(t);
dp[x][0]+=max(dp[t][1],dp[t][0]);
dp[x][1]+=dp[t][0];
}
}
dfs(root);
cout<<max(dp[root][0],dp[root][1])<<endl;
具体代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
typedef long long ll;
const int N=6010;
int m,n;
int dp[N][2],rd[N];
vector <int>tu[N];
void dfs(int x)
{
int l=tu[x].size();
for(int i=0;i<l;i++)
{
int t=tu[x][i];
dfs(t);
dp[x][0]+=max(dp[t][1],dp[t][0]);
dp[x][1]+=dp[t][0];
}
}
int main()
{
while(~scanf("%d",&n))