BZOJ2427 浅谈TARJAN缩点 和 树形依赖背包动态规划

前端之家收集整理的这篇文章主要介绍了BZOJ2427 浅谈TARJAN缩点 和 树形依赖背包动态规划前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


世界真的很大
(还是纪念fate)
动态规划的题很常见了
其中背包问题也是屡见不鲜
而有时各个物品间有各种依赖关系,构成一颗树状的结构
有人将其称之为
树形依赖背包动态规划
还是先看一下题:
Description

  1. 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
  2.  
  3. 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0
  4.  
  5. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

input

  1. 1行:N,M 0<=N<=100,0<=M<=500
  2. 2行:W1,W2,... Wi,...,Wn 0<=Wi<=M
  3. 3行:V1,V2,Vi,Vn 0<=Vi<=1000
  4. 4行:D1,D2,Di,Dn 0<=Di<=N,Dii

output

  1. 一个整数,代表最大价值。

其实能从题意里轻松读出来这是背包问题。
每一个物品向它依赖的物品连边,形成一种树形的结构,每个没有依赖的物品就是根节点。要想要每一个物品,它到它根节点的所有物品全都要取。
但这样就可能不止一棵树了
很容易想到虚拟一个点(如0)来作为所有树的根节点,这样就是一棵树了。再跑一遍树形依赖背包动态规划,就完事儿了
但这样有一个很坑的错误
每种联通的依赖关系,不见得是一棵树
比如1依赖2,2依赖1,没有问题.
所以不能直接虚拟一个点。
先用tarjan缩点,连边,这样才得到了很多的树,虚拟一个根节点,跑一遍树形dp就行了
完整代码

  1. #include<stdio.h>
  2. #include<cstring>
  3. #include<stack>
  4. using namespace std;
  5.  
  6. stack <int> state;
  7.  
  8. struct edge
  9. {
  10. int last,u,v;
  11. }ed[100010],ad[100010];
  12.  
  13. int num=0,mum=0,ans=0,cnt=0,n,m,idx=0,INF=1e9;
  14. int head[1010],dfn[1010],low[1010],ins[1010],f[110][510];
  15. int w[110],v[110],pt[110],vis[110],in[510],ww[110],vv[110],hed[10010];
  16.  
  17. void add(int u,int v)
  18. {
  19. num++;
  20. ed[num].last=head[u];
  21. ed[num].v=v;
  22. ed[num].u=u;
  23. head[u]=num;
  24. }
  25.  
  26. void ade(int u,int v)
  27. {
  28. mum++;
  29. in[v]++;
  30. ad[mum].v=v;
  31. ad[mum].last=hed[u];
  32. hed[u]=mum;
  33. }
  34.  
  35. void tarjan(int u)
  36. {
  37. dfn[u]=low[u]=++idx;
  38. vis[u]=ins[u]=1;
  39. state.push(u);
  40. for(int i=head[u];i;i=ed[i].last)
  41. {
  42. int v=ed[i].v;
  43. if(!vis[v])
  44. {
  45. tarjan(v);
  46. low[u]=min(low[u],low[v]);
  47. }
  48. else if(ins[v])
  49. {
  50. low[u]=min(low[u],dfn[v]);
  51. }
  52. }
  53. if(dfn[u]==low[u])
  54. {
  55. cnt++;int t=-1;
  56. while(t!=u)
  57. {
  58. t=state.top();
  59. pt[t]=cnt;
  60. ww[cnt]+=w[t];
  61. vv[cnt]+=v[t];
  62. ins[t]=0;
  63. state.pop();
  64. }
  65. }
  66. }
  67.  
  68. void dfs(int u)
  69. {
  70. for(int i=hed[u];i;i=ad[i].last)
  71. {
  72. int v=ad[i].v;
  73. dfs(v);
  74. for(int k=m;k>=0;k--)
  75. for(int j=k;j>=0;j--)
  76. f[u][k]=max(f[u][k],f[u][k-j]+f[v][j]);
  77. }
  78. for(int j=m;j>=0;j--)
  79. {
  80. if(j>=ww[u]) f[u][j]=f[u][j-ww[u]]+vv[u];
  81. else f[u][j]=0;
  82. }
  83. }
  84.  
  85. void rebuild()
  86. {
  87. memset(head,0,sizeof(head));
  88. for(int i=1;i<=num;i++)
  89. if(pt[ed[i].u]!=pt[ed[i].v])
  90. {
  91. ade(pt[ed[i].u],pt[ed[i].v]);
  92. in[pt[ed[i].v]]++;
  93. }
  94. }
  95.  
  96. int main()
  97. {
  98. scanf("%d%d",&n,&m);
  99. for(int i=1;i<=n;i++)
  100. scanf("%d",&w[i]);
  101. for(int i=1;i<=n;i++)
  102. scanf("%d",&v[i]);
  103. for(int i=1;i<=n;i++)
  104. {
  105. int u;
  106. scanf("%d",&u);
  107. add(u,i);
  108. }
  109. for(int i=0;i<=n;i++)
  110. if(!vis[i]) tarjan(i);
  111. rebuild();
  112. int s;
  113. for(int i=1;i<=cnt;i++)
  114. if(!in[i]) ade(cnt+1,i);
  115. dfs(cnt+1);
  116. printf("%d",f[cnt+1][m]);
  117. return 0;
  118. }

嗯,就是这样

猜你在找的设计模式相关文章