【算法笔记】树形dp
·前言
树形dp,顾名思义,就是在树上进行的dp,它一般会搭配上深度优先搜索进行,以记录下所以的孩子/父亲的状态用于转移
(可能会出现一大堆的计数题,感觉这种dp特别适合用来整计数)
·基本思维
树形dp最大的特点就是在一边搜索的时候一边记录答案,这样子的话调用答案的时候会比较方便。而且,当遇到图论题的时候,其实也可以把图转化成一棵树来解决问题。
比较简单的树形dp思路相对好想,码量也不算大(但是难打的树形dp思路就会特别毒瘤,根本就想不出来啊……
这里给出一些树形dp比较常用的板子:
·树的最大独立集
#include<bits/stdc++.h> using namespace std; int n,f[100010][25],g[100010],s[100010],d[100010]; vector<int>v[100010]; void dfs(int x,int fa){ for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1]; for(int i=0;i<v[x].size();i++){ int to=v[x][i]; if(to==fa)continue; f[to][0]=x; dfs(to,x); } d[x]=max(s[x],g[x]+1); s[f[x][0]]+=d[x]; g[f[x][1]]+=d[x]; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); v[x].push_back(y); v[y].push_back(x); } dfs(1,0); printf("%d",d[1]); return 0; }
·树的重心
#include<bits/stdc++.h> using namespace std; int son[100010],vis[100010],n,size,ans; vector<int>v[100010]; void dfs(int x){ vis[x]=1;son[x]=0; int maxn=0; for(int i=0;i<v[x].size();i++){ int to=v[x][i]; if(!vis[to]){ dfs(to); son[x]+=son[to]+1; maxn=max(maxn,son[to]+1); } } maxn=max(maxn,n-son[x]-1); if(maxn<size||maxn==size&&x<ans)ans=x,size=maxn; } int main(){ scanf("%d",&n); size=1e9; for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); v[x].push_back(y); v[y].push_back(x); } dfs(1); printf("%d %d\n",ans,size); return 0; }
·树上最长路径
#include<bits/stdc++.h> using namespace std; int n,vis[200010],d[200010]; vector<int>v[200010]; int spfa(int u){ queue<int>q; memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); q.push(u); d[u]=0;vis[u]=1; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=0;i<v[x].size();i++){ int to=v[x][i]; if(d[to]>d[x]+1){ d[to]=d[x]+1; if(!vis[to]){ vis[to]=1; q.push(to); } } } vis[x]=0; } int maxn=0,id; for(int i=1;i<=n;i++) if(i!=u){ if(d[i]>maxn)id=i,maxn=d[i]; } return id; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); v[x].push_back(y); v[y].push_back(x); } int ans=0,id=spfa(1); ans+=d[id]; int ans1=ans,id2=spfa(id); if(id==1)ans=max(ans,d[id2]); else ans+=d[id2]; printf("%d\n",ans-ans1); return 0; }
·题目汇总
poj2342/hdu1520 Anniversary party
hdu6201 transaction transaction transaction
hdu2196 Computer
Luogu2014 CTSC1997
hdu6035 Colorful Tree
codeforces 1101D/990G Gcd Counting
Luogu3177 HAOI2015
UVA10859 Placing Lampposts
*先不放链接啦,先把题目放在这里,以后会把代码补上。