HAOI2010软件安装(树形背包)

题意

  有n个物品,每个物品最多会依赖一个物品,但一个物品可以依赖于一个不独立(依赖于其它物品)的物品,且可能有多个物品依赖一个物品,并且依赖关系可能形成一个环。现给你V的资金,问如何分配资金,可以使你的得到的总价值最大,请求出这个总价值。

解法

  我以前写过对于普通依赖性背包的博客:noip2006金明的预算方案如果对依赖性背包不是很熟悉的同学可以先看一下这道题。

由于这道题的依赖关系可能形成环,所以我们先用tarjan缩一下点,然后依赖关系图就变成了一个森林,这时候我们再将每一棵树的根节点向0号结点连一条边,表示他们依赖0号结点。这时候我们就得到了一颗依赖关系树。

那么现在的重点就在如何处理这颗依赖关系树。因为树上每一个节点的决策数都太大了,所以同样的我们考虑求出每一个以i节点为根的子树在任意权值下的最大价值,然后再在i节点利用01背包来合并,一直递归往上。最后的答案就是0号结点所有方案中最优的那一个。

ps:如果还是看不懂的话,可以参观这里这里我也是在那儿学的。

代码

以下的代码是 \(O(nv^2)\) 的:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <cctype>
  8. #include <vector>
  9. #define INF 2139062143
  10. #define MAX 0x7ffffffffffffff
  11. #define del(a,b) memset(a,b,sizeof(a))
  12. using namespace std;
  13. typedef long long ll;
  14. template<typename T>
  15. inline void read(T&x)
  16. {
  17. x=0;T k=1;char c=getchar();
  18. while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
  19. while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
  20. }
  21. const int maxn=2500+15;
  22. int w[maxn],cost[maxn];
  23. int n,m,ecnt;
  24. struct Edge{
  25. int u,v;
  26. Edge(int u,int v):u(u),v(v){}
  27. };
  28. vector<Edge> edge;
  29. vector<int> G[maxn];
  30. void add_edge(int u,int v) {
  31. edge.push_back(Edge(u,v));
  32. ecnt=edge.size();
  33. G[u].push_back(ecnt-1);
  34. }
  35. int dfn[maxn],low[maxn],sta[maxn],top,bl[maxn],cnt;
  36. bool ins[maxn];
  37. void tarjian(int u) {
  38. ins[u]=1;sta[++top]=u;
  39. dfn[u]=low[u]=++cnt;
  40. for(int i=0;i<G[u].size();i++) {
  41. Edge e=edge[G[u][i]];
  42. int v=e.v;
  43. if(!dfn[v]) {
  44. tarjian(v);
  45. low[u]=min(low[u],low[v]);
  46. }
  47. else if(ins[v]) low[u]=min(low[u],dfn[v]);
  48. }
  49. if(low[u]==dfn[u]) {
  50. int y;
  51. while((y=sta[top--])&&y) {
  52. bl[y]=u;
  53. ins[y]=0;
  54. if(u==y) break;
  55. w[u]+=w[y],cost[u]+=cost[y];
  56. }
  57. }
  58. }
  59. int dp[maxn][maxn];
  60. void dfs(int u) {
  61. dp[u][cost[u]]=w[u];
  62. for(int i=0;i<G[u].size();i++) {
  63. Edge e=edge[G[u][i]];
  64. int v=e.v;
  65. dfs(v);
  66. for(int i=m;i>=cost[u];i--)
  67. for(int j=0;j<=i-cost[u];j++)
  68. dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[v][j]);
  69. }
  70. }
  71. bool noroot[maxn];
  72. int main()
  73. {
  74. read(n),read(m);
  75. for(int i=1;i<=n;i++) read(cost[i]);
  76. for(int i=1;i<=n;i++) read(w[i]);
  77. for(int i=1;i<=n;i++) {
  78. int d;read(d);
  79. if(!d) continue;
  80. add_edge(d,i);
  81. }
  82. for(int i=1;i<=n;i++) if(!dfn[i]) tarjian(i);
  83. int k=edge.size();
  84. for(int i=0;i<=n;i++) G[i].clear();
  85. for(int i=0;i<k;i++) {
  86. Edge e=edge[i];
  87. int f1=bl[e.u],f2=bl[e.v];
  88. if(f1==f2) continue;// 新的两个点可能在同一个强连通分量中!!
  89. add_edge(f1,f2);noroot[f2]=1;
  90. }
  91. for(int i=1;i<=n;i++) if((bl[i]==i)&&(!noroot[i])) add_edge(0,i);
  92. dfs(0);
  93. int ans=0;
  94. for(int i=0;i<=m;i++)
  95. ans=max(ans,dp[0][i]);
  96. printf("%d\n",ans);
  97. return 0;
  98. }

这下面的是参照徐持横的算法做到的 \(O(nv)\) 的算法:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <cctype>
  8. #include <vector>
  9. #define INF 2139062143
  10. #define MAX 0x7ffffffffffffff
  11. #define del(a,b) memset(a,b,sizeof(a))
  12. using namespace std;
  13. typedef long long ll;
  14. template<typename T>
  15. inline void read(T&x)
  16. {
  17. x=0;T k=1;char c=getchar();
  18. while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
  19. while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
  20. }
  21. const int maxn=500+15;
  22. int w[maxn],cost[maxn];
  23. int n,m,ecnt;
  24. struct Edge{
  25. int u,v;
  26. Edge(int u,int v):u(u),v(v){}
  27. };
  28. vector<Edge> edge;
  29. vector<int> G[maxn];
  30. void add_edge(int u,int v) {
  31. edge.push_back(Edge(u,v));
  32. ecnt=edge.size();
  33. G[u].push_back(ecnt-1);
  34. }
  35. int dfn[maxn],low[maxn],sta[maxn],top,bl[maxn],cnt;
  36. bool ins[maxn];
  37. void tarjian(int u) {
  38. ins[u]=1;sta[++top]=u;
  39. dfn[u]=low[u]=++cnt;
  40. for(int i=0;i<G[u].size();i++) {
  41. Edge e=edge[G[u][i]];
  42. int v=e.v;
  43. if(!dfn[v]) {
  44. tarjian(v);
  45. low[u]=min(low[u],low[v]);
  46. }
  47. else if(ins[v]) low[u]=min(low[u],dfn[v]);
  48. }
  49. if(low[u]==dfn[u]) {
  50. int y;
  51. while((y=sta[top--])&&y) {
  52. bl[y]=u;
  53. ins[y]=0;
  54. if(u==y) break;
  55. w[u]+=w[y],cost[u]+=cost[y];
  56. }
  57. }
  58. }
  59. int dp[maxn][maxn];
  60. void dfs(int u,int M) {
  61. if(M<=0) return;
  62. for(int i=0;i<G[u].size();i++) {
  63. Edge e=edge[G[u][i]];
  64. int v=e.v;
  65. for(int j=1;j<=M;j++) dp[v][j]=dp[u][j];
  66. dfs(v,M-cost[v]);
  67. for(int j=cost[v];j<=M;j++) dp[u][j]=max(dp[u][j],dp[v][j-cost[v]]+w[v]);
  68. }
  69. }
  70. bool noroot[maxn];
  71. int main()
  72. {
  73. read(n),read(m);
  74. for(int i=1;i<=n;i++) read(cost[i]);
  75. for(int i=1;i<=n;i++) read(w[i]);
  76. for(int i=1;i<=n;i++) {
  77. int d;read(d);
  78. if(!d) continue;
  79. add_edge(d,i);
  80. }
  81. for(int i=1;i<=n;i++) if(!dfn[i]) tarjian(i);
  82. int k=edge.size();
  83. for(int i=0;i<=n;i++) G[i].clear();
  84. for(int i=0;i<k;i++) {
  85. Edge e=edge[i];
  86. int f1=bl[e.u],f2=bl[e.v];
  87. if(f1==f2) continue;// 新的两个点可能在同一个强连通分量中!!
  88. add_edge(f1,f2);noroot[f2]=1;
  89. }
  90. for(int i=1;i<=n;i++) if((bl[i]==i)&&(!noroot[i])) add_edge(0,i);
  91. dfs(0,m);
  92. int ans=0;
  93. for(int i=0;i<=m;i++) ans=max(ans,dp[0][i]);
  94. printf("%d",ans);
  95. return 0;
  96. }

HAOI2010软件安装(树形背包)的更多相关文章

  1. BZOJ2427:[HAOI2010]软件安装(树形DP,强连通分量)

    Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...

  2. 【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包

    [BZOJ2427][HAOI2010]软件安装 Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为 ...

  3. BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP

    BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP 题意: 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁 ...

  4. Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装

    [洛谷P2515][HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得 ...

  5. [HAOI2010]软件安装(Tarjan,树形dp)

    [HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可 ...

  6. bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp

    [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2029  Solved: 811[Submit][Status][Dis ...

  7. 洛谷 P2515 [HAOI2010]软件安装 解题报告

    P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到 ...

  8. [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)

    2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1987  Solved: 791[Submit][Statu ...

  9. bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)

    2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1053  Solved: 424[Submit][Statu ...

随机推荐

  1. spring boot项目Intellij 打包

    spring boot项目Intellij 打包 学习了:http://blog.csdn.net/hzt_fighting_up/article/details/78174291 在edit con ...

  2. Python常用模块【sys】

    sys.argv 参数    「argv」是「argument variable」参数变量的简写形式.一般在命令行调用的时候由系统传递给程序.这个变量其实是一个List列表,argv[0] 一般是“被 ...

  3. poj2342 Anniversary party (树形dp)

    poj2342 Anniversary party (树形dp) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9128   ...

  4. P1850 换教室 概率dp

    其实说是概率dp,本质上和dp没什么区别,就是把所有可能转移的情况全枚举一下就行了,不过dp方程确实有点长... ps:这个题的floyed我竟然之前写跪了... 题目: 题目描述 对于刚上大学的牛牛 ...

  5. [python 基础]python装饰器(一)添加functools获取原函数信息以及functools.partial分析

    python装饰器学习的时候有两点需要注意一下 1,被装饰器装饰的函数取其func.__name__和func.func_doc的时候得到的不是被修饰函数的相关信息而是装饰器wrapper函数的doc ...

  6. 洛谷P2593 [ ZJOI 2006 ] 超级麻将 —— DP

    题目:https://www.luogu.org/problemnew/show/P2593 DP的话,考虑到当前这一位只跟前两位有关,所以记录一下这3位的状态就行: 于是一开始记录的第 i 位,i- ...

  7. iOS开发之KVC全解

    一  KVC的基本概念 1.KVC是Key Value Coding的缩写,意思是键值编码. 在iOS中,提供了一种方法通过使用属性的名称(也就是Key)来间接访问对象属性的方法,这个方法可以不通过g ...

  8. Java获取NTP网络时间

    最近项目中涉及到一个时间验证的问题,需要根据当前时间来验证业务数据是否过期.所以直接写代码如下: new java.util.Date().getTime();          结果测试的时候出现了 ...

  9. kafka与zookeeper实战笔记

    kafka命令 1.先启动zookeeper zkServer.cmd/zkServer.sh2.启动kafka[需要指定server.properties文件] kafka-server-start ...

  10. chapter6 数据结构基础之习题 Parentheses Balance

    You are given a string consisting of parentheses () and []. A string of this type is said to be corr ...