T180034 树形背包 题解(动态规划的序关系)
直接暴力搞树形DP是会爆的,时间复杂度在$O(n^2m)$左右,据说也可以通过某些方法把树形dp优化到$O(nm)$
这里提供另外一种 离 奇 的方法:
首先考虑一棵树的情况,当某一个节点不选时,我们可以将其直接转移到同根的下一个子树,如果某一个节点选择时,那么就可以将其转移到它的所有儿子。
预处理一个dfn(dfs序)和一个next数组就可以完成任务了。
看代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,w[100001],v[100001],pre[100001],head[1000001],cnt; 7 struct node 8 { 9 int to,next; 10 }a[1000001]; 11 void add_edge(int from,int to) 12 { 13 a[++cnt].to=to; 14 a[cnt].next=head[from]; 15 head[from]=cnt; 16 } 17 int b[100001],nxt[1000001],fa[1000001],dfn[1000001],times,f[1111][11111][2];//重量为i的背包,当前这个选\没选的价值是多少 18 void dfs(int u) 19 { 20 b[u]=1; 21 dfn[times]=u; 22 int now=times; 23 times++; 24 for(int i=head[u];i;i=a[i].next)dfs(a[i].to); 25 nxt[now]=times; 26 } 27 int main() 28 { 29 cin>>n>>m; 30 for(int i=1;i<=n;i++) 31 { 32 cin>>w[i]>>v[i]>>pre[i]; 33 if(pre[i]!=i)add_edge(pre[i],i),b[i]++; 34 } 35 for(int i=1;i<=n;i++) 36 for(int j=0;j<=m;j++) 37 f[i][j][0]=f[i][j][1]=-1e9; 38 f[0][0][0]=f[0][0][1]=0; 39 times=1; 40 for(int i=1;i<=n;i++)if(!b[i])dfs(i); 41 for(int i=0;i<n;i++)//物品 42 { 43 for(int j=0;j<=m;j++)//重量 44 { 45 f[i+1][j+w[dfn[i+1]]][1]=max(f[i+1][j+w[dfn[i+1]]][1],f[i][j][1]+v[dfn[i+1]]); //选 46 f[i+1][j][0]=max(f[i+1][j][0],f[i][j][1]); 47 f[nxt[i]][j+w[dfn[nxt[i]]]][1]=max(f[nxt[i]][j+w[dfn[nxt[i]]]][1],f[i][j][0]+v[dfn[nxt[i]]]);//不选,跳过 48 f[nxt[i]][j][0]=max(f[nxt[i]][j][0],f[i][j][0]); 49 } 50 } 51 cout<<max(f[n][m][0],f[n][m][1]); 52 53 }
我要吐了
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15003721.html