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

[HAOI2010]软件安装

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2029  Solved: 811
[Submit][Status][Discuss]

Description

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

但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。

我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

 

Input

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

 

Output

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

 

Sample Input

3 10
5 5 6
2 3 4
0 1 1

Sample Output

5

HINT

 
树形,dp依赖型的,算完点,是一棵树对吧,然后就从根向下dp数据范围如此之小。
f[i][j]表示i这个点,可以用安装连续几个点的方案数。
 
  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdio>
  6 
  7 #define N 107
  8 #define M 507
  9 using namespace std;
 10 inline int read()
 11 {
 12     int x=0,f=1;char ch=getchar();
 13     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
 14     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 
 18 int n,m,cnt,scc,ind,top;
 19 int v[N],w[N];
 20 int sv[N],sw[N];
 21 int dfn[N],low[N],belong[N];
 22 int q[N],f[N][M],in[M];
 23 struct edge{
 24     int to,next;
 25 }e[M],ed[M];int last[N],last2[N];
 26 bool inq[N];
 27 
 28 void insert(int u,int v){e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;}
 29 void insert2(int u,int v)
 30 {
 31     in[v]=1;
 32     ed[++cnt].to=v;ed[cnt].next=last2[u];last2[u]=cnt;
 33 }
 34 void tarjan(int x)
 35 {
 36     int now=0;
 37     low[x]=dfn[x]=++ind;
 38     q[++top]=x;inq[x]=1;
 39     for(int i=last[x];i;i=e[i].next)
 40         if(!dfn[e[i].to])
 41         {
 42             tarjan(e[i].to);
 43             low[x]=min(low[x],low[e[i].to]);
 44         }
 45         else if(inq[e[i].to])
 46             low[x]=min(low[x],dfn[e[i].to]);
 47     if(low[x]==dfn[x])
 48     {
 49         scc++;
 50         while(now!=x)
 51         {
 52             now=q[top--];inq[now]=0;
 53             belong[now]=scc;
 54             sv[scc]+=v[now];
 55             sw[scc]+=w[now];
 56         }
 57     }
 58 }
 59 void rebuild()
 60 {
 61     cnt=0;
 62     for(int x=1;x<=n;x++)
 63         for(int i=last[x];i;i=e[i].next)
 64             if(belong[e[i].to]!=belong[x])
 65                 insert2(belong[x],belong[e[i].to]);
 66 }
 67 void dp(int x)
 68 {
 69     for(int i=last2[x];i;i=ed[i].next)
 70     {
 71         dp(ed[i].to);
 72         for(int j=m-sw[x];j>=0;j--)
 73         {
 74             for(int k=0;k<=j;k++)
 75                 f[x][j]=max(f[x][j],f[x][k]+f[ed[i].to][j-k]);        
 76         }
 77     }
 78     for(int j=m;j>=0;j--)
 79     {
 80         if(j>=sw[x])f[x][j]=f[x][j-sw[x]]+sv[x];
 81         else f[x][j]=0;
 82     }
 83 }
 84 int main()
 85 {
 86     n=read();m=read();
 87     for(int i=1;i<=n;i++) w[i]=read();
 88     for(int i=1;i<=n;i++) v[i]=read();
 89     for(int i=1;i<=n;i++)
 90     {
 91         int x=read();
 92         if(x)insert(x,i);
 93     }
 94     for(int i=1;i<=n;i++)
 95         if(!dfn[i])tarjan(i);
 96     rebuild();
 97     for(int i=1;i<=scc;i++)
 98         if(!in[i])
 99             insert2(scc+1,i);
100     dp(scc+1);
101     printf("%d\n",f[scc+1][m]);
102 }

 

 
posted @ 2018-04-08 16:50  Kaiser-  阅读(164)  评论(0编辑  收藏  举报