0x54 树形DP
Posted akcqhzdy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0x54 树形DP相关的知识,希望对你有一定的参考价值。
树形DP我只知道千万别写森林转二叉树慢的要死
没有上司的舞会 水!裸!
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[6100];int len,last[6100]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int f[6100][2],h[6100]; void treedp(int x) { f[x][0]=0;f[x][1]=h[x]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; treedp(y); f[x][0]+=max(f[y][0],f[y][1]); f[x][1]+=f[y][0]; } } int fa[6100]; int main() { int n,x,y; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&h[i]); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); ins(y,x);fa[x]=y; } int rt; for(int i=1;i<=n;i++) if(fa[i]==0)rt=i; treedp(rt); printf("%d ",max(f[rt][0],f[rt][1])); return 0; }
选课 带个背包咯,注意一下背包别重复用一个子节点就好
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[310];int len,last[310]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int f[310][310],h[310],tot[310]; void treedp(int x) { f[x][1]=h[x];tot[x]=1; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; treedp(y); for(int i=tot[x];i>=1;i--) for(int j=tot[y];j>=1;j--) f[x][i+j]=max(f[x][i+j],f[x][i]+f[y][j]); tot[x]+=tot[y]; } } int fa[310]; int main() { int n,m,x,y; scanf("%d%d",&n,&m); h[0]=0; for(int i=1;i<=n;i++) { scanf("%d%d",&fa[i],&h[i]); ins(fa[i],i); } memset(f,-1,sizeof(f)); treedp(0); printf("%d ",f[0][m+1]); return 0; }
poj3585 这题还挺有意思哈,书上说这是“不定根”的树形DP问题,有个很高大上的名词叫二次扫描与换根法
其实自己YY一下,设1为根,第一次dfs把每个点管辖的子树的流量d算出来,对于一个点其实它的流量就是这个d值+从父节点流出去的流量,画个图还是很好解决的,就是min(到父节点的边权,父节点的d值-当前点给父节点的贡献)
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,c,next; }a[410000];int len,last[210000]; void ins(int x,int y,int c) { len++; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; } bool checkleaf(int x,int fr) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr)return false; } return true; } int d[210000]; void dfs(int x,int fr) { d[x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr) { dfs(y,x); if(checkleaf(y,x)==true)d[x]+=a[k].c; else d[x]+=min(a[k].c,d[y]); } } } int mmax; void solve(int x,int fr,int rd) { mmax=max(mmax,d[x]+rd); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fr) { int g; if(checkleaf(y,x)==true)g=d[x]-a[k].c; else g=d[x]-min(a[k].c,d[y]); if(checkleaf(x,y)==true)solve(y,x,a[k].c); else solve(y,x,min(rd+g,a[k].c)); } } } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); int T; scanf("%d",&T); while(T--) { int n,x,y,c; scanf("%d",&n); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&c); ins(x,y,c);ins(y,x,c); } dfs(1,0); mmax=0;solve(1,0,0); printf("%d ",mmax); } return 0; }
以上是关于0x54 树形DP的主要内容,如果未能解决你的问题,请参考以下文章
动态规划_计数类dp_数位统计dp_状态压缩dp_树形dp_记忆化搜索
Starship Troopers(HDU 1011 树形DP)