[bzoj2427] [HAOI2010] 软件安装(强连通分量)(树形背包DP)

Posted oi-zzyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj2427] [HAOI2010] 软件安装(强连通分量)(树形背包DP)相关的知识,希望对你有一定的参考价值。

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

 

题解:
  先看一下题面,体积?空间?那肯定是背包啊。于是作者便高高兴兴地打出状态转移方程:

dp[i][j]=max(dp[i][j],dp[i-1][j-w[x]]+v[x]) (错解)

  于是喜提一0分。。。

  本题正解其实就是背包dp,又因为题干中说 一个软件最多依赖另外一个软件(每个节点最多只有一个出度) 那应该就是一个树上dp(作者表示连这是一棵树也要看不出来了)。

  于是作者又高高兴兴地打出状态转移方程(分组背包模型):

dp[i][j]=ΣiL=0 ΣjR=0 max(dp[L][R])+v[x] (正解)

  于是又喜提一0分。。。

  考虑一下:每个节点最多只有一个出度,它就一定是一棵树吗?显然不是。这就需要我们用 tarjan 缩点来解决(合并权值与体积为一点,重新建图)。

  交上代码,又双是0分。。。

  最终其实错在了:在最终加上现节点的权值时(上面更新的是贡献最大子节点权值和),需要将体积小于 现节点的体积 的情况归零(我们上面更新的就是 给现节点的体积留有位置时的情况,针对不满足的情况就需归0)。

  还有一种打法:先加上现节点的权值,再进行比较,求最大值。当现在节点所枚举到的体积与子节点所枚举到的体积相等时,即未选现节点的权值时,需要特殊处理,防止更新出类似完全背包一样的重复的情况。

Code:

技术图片
  1 #include<cstdio>
  2 #include<cstring>
  3 #define $ 110
  4 using namespace std;
  5 int n,m,v[$],w[$],d[$],dp[$][$*5],ans,dfn[$],low[$],tar,sta[$],up,circle=1,cir[$];
  6 int wc[$],vc[$],second[$],first[$],tot1,tot2,sum[$],out[$];
  7 bool judge[$];
  8 struct tree    int to,next;    a[$],b[$];
  9 inline int read()
 10     char a=getchar();
 11     int sum=0;
 12     while(a<0||a>9)   a=getchar();
 13     while(a>=0&&a<=9) sum=(sum<<1)+(sum<<3)+a-0,a=getchar();
 14     return sum;
 15 
 16 inline int max(int x,int y)    return x>y?x:y;    
 17 inline int min(int x,int y)    return x<y?x:y;    
 18 inline void add(int x,int y)
 19     a[++tot1]=(tree)    y,first[x]    ;
 20     first[x]=tot1;
 21 
 22 inline void addf(int x,int y)
 23     b[++tot2]=(tree)    y,second[x]    ;
 24     second[x]=tot2;
 25 
 26 inline void tarjan(int x)
 27     dfn[x]=low[x]=++tar;
 28     sta[++up]=x;
 29     judge[x]=1;
 30     for(register int i=second[x];i;i=b[i].next)
 31         int to=b[i].to;
 32         if(!dfn[to])    
 33             tarjan(to);
 34             low[x]=min(low[x],low[to]);
 35         
 36         else if(judge[to]) low[x]=min(low[x],dfn[to]);
 37     
 38     if(dfn[x]==low[x])
 39         int tmp;  ++circle;
 40         do
 41             tmp=sta[up--];
 42             judge[tmp]=0;
 43             cir[tmp]=circle;
 44             w[circle]+=wc[tmp];
 45             v[circle]+=vc[tmp];
 46         while(tmp!=x);
 47     
 48 
 49 inline void dfs(int x)
 50     for(register int i=first[x];i;i=a[i].next)
 51         int to=a[i].to;
 52         dfs(to);
 53         for(register int j=m;j>=0;--j)
 54             for(register int k=j;k>=0;--k)
 55                 dp[x][j]=max(dp[x][j],dp[x][k]+dp[to][j-k]);
 56             
 57         
 58     
 59     for(register int i=m;i>=w[x];--i)   dp[x][i]=dp[x][i-w[x]]+v[x];
 60     for(register int i=w[x]-1;i>=0;--i) dp[x][i]=0;
 61 
 62 /*
 63 void DP(int x)
 64 
 65     for(int i=bit[x];i<=m;i++)
 66         dp[x][i]=val[x];
 67     for(int i=fi[x];i!=0;i=e[i].ne)
 68     
 69         int y=e[i].v;
 70         DP(y);
 71         for(int j=m;j>=bit[x];j--)
 72         
 73             int temp=dp[x][j];
 74             for(int k=bit[x];k<=j-bit[y];k++)
 75             
 76                 if(k!=j)
 77                     dp[x][j]=max(dp[x][j],dp[x][k]+dp[y][j-k]);
 78                 else
 79                     dp[x][j]=max(dp[x][j],temp+dp[y][j-k]);
 80             
 81         
 82     
 83 */
 84 signed main()
 85     scanf("%d%d",&n,&m);
 86     for(register int i=1;i<=n;++i) wc[i]=read();
 87     for(register int i=1;i<=n;++i) vc[i]=read();
 88     for(register int i=1,x;i<=n;++i) if(x=read()) addf(x,i);
 89     for(register int i=1;i<=n;++i)   if(!dfn[i])  tarjan(i);
 90     for(register int i=1;i<=n;++i)
 91         for(register int j=second[i];j;j=b[j].next)
 92             int to=b[j].to;
 93             if(cir[i]!=cir[to]) add(cir[i],cir[to]),out[cir[to]]++;
 94         
 95     for(register int i=2;i<=circle;++i) if(!out[i]) add(1,i);
 96     dfs(1);
 97     for(register int i=0;i<=m;++i) ans=max(ans,dp[1][i]);
 98     printf("%d\n",ans);
 99 
100             
View Code

 

以上是关于[bzoj2427] [HAOI2010] 软件安装(强连通分量)(树形背包DP)的主要内容,如果未能解决你的问题,请参考以下文章

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

BZOJ2427: [HAOI2010]软件安装

BZOJ2427[HAOI2010]软件安装 Tarjan+树形背包

bzoj 2427: [HAOI2010]软件安装

BZOJ2427: [HAOI2010]软件安装

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