1、什么是树型动态规划
树型动态规划就是在“树”的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺推与逆推,而树型动态规划是建立在树上的,所以也相应的有二个方向:
1、叶->根:在回溯的时候从叶子节点往上更新信息(一般都是从叶到根)
2、根 - >叶:往往是在从叶往根dfs一遍之后(相当于预处理),再重新往下获取最后的答案。
2、树形动态规划的优美之处
树本身至少就有“子结构”性质(树和子树);也本身就具有递归性。所以在树上DP其实是其所当然的事,相比线性动态规划来讲,转移方程更直观,更易理解。
HDU 1520 Anniversary party
题目描述:每个节点都有一个权值,子节点和父亲节点不能同时选,问最大价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
解题思路:任何一个点的取舍可以看作一种决策,那么状态就是在某个点取的时候或者不取的时候,以他为根的子树能有的最大权值。分别可以用f[i,1]和f[i,0]表示节点i选或者不选。
当选了节点i时,f[i,1]+=f[j,0] //j为i的子节点
当不选节点i时,f[i,0]+=max(f[j,0],f[j,1]) //不选节点i时它的子节点可以选也可以不选
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn=1e6+10;
int n;
ll f[maxn][2],a[maxn];
vector<int> e[maxn];
void dfs(int x){
for(int i=0;i<e[x].size();i++){
int u=e[x][i];
dfs(u);
f[x][0]+=max(f[u][1],f[u][0]);
f[x][1]+=f[u][0];
}
}
int main()
{
int x,y;
while(scanf("%d",&n)!=EOF){
rep(i,1,n) scanf("%d",&a[i]),e[i].clear(),f[i][0]=0,f[i][1]=a[i];
map<int,int> mp;
while(1){
scanf("%d%d",&x,&y);
if(x==0&&y==0) break;
e[y].pb(x);
mp[x]=1;
}
int root;
rep(i,1,n) if(!mp[i]) root=i;
dfs(root);
cout<<max(f[root][0],f[root][1])<<endl;
}
return 0;
}