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

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

Solution 

首先按依赖关系建个图……然后tarjan缩个点……缩完后会是若干棵树的形态……
将若干棵树连向一个根然后DP……设f[x][i]表示在x点装了空间i的最大价值……

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define N (1000000+1000)
 5 using namespace std;
 6 
 7 struct Edge{int to,next;}edge[N];
 8 int Dfn[N],Low[N],Col[N],stack[N],Ind[N],top,dfs_num,col_num;
 9 int n,m,w[N],v[N],d[N],W[N],V[N],head[N],f[105][505],num_edge;
10 bool vis[N];
11 
12 void add(int u,int v)
13 {
14     edge[++num_edge].to=v;
15     edge[num_edge].next=head[u];
16     head[u]=num_edge;
17 }
18 
19 void Tarjan(int x)
20 {
21     Dfn[x]=Low[x]=++dfs_num;
22     stack[++top]=x; vis[x]=true;
23     for (int i=head[x]; i; i=edge[i].next)
24         if (!Dfn[edge[i].to])
25             Tarjan(edge[i].to),Low[x]=min(Low[x],Low[edge[i].to]);
26         else if (vis[edge[i].to])
27             Low[x]=min(Low[x],Dfn[edge[i].to]);
28     if (Dfn[x]==Low[x])
29     {
30         vis[x]=false; Col[x]=++col_num;
31         W[col_num]=w[x]; V[col_num]=v[x];
32         while (stack[top]!=x)
33         {
34             vis[stack[top]]=false;
35             Col[stack[top]]=col_num;
36             W[col_num]+=w[stack[top]];
37             V[col_num]+=v[stack[top--]];
38         }
39         --top;
40     }
41 }
42 
43 void DP(int x)
44 {
45     for(int i=head[x]; i; i=edge[i].next)
46     {
47         DP(edge[i].to);
48         for(int j=m-W[x]; j>=0; --j)
49             for(int k=0; k<=j; ++k)
50                 f[x][j]=max(f[x][j],f[x][k]+f[edge[i].to][j-k]);        
51     }
52     for(int j=m;j>=0;j--)
53     {
54         if(j>=W[x]) f[x][j]=f[x][j-W[x]]+V[x];
55         else f[x][j]=0;
56     }
57 }
58 
59 int main()
60 {
61     scanf("%d%d",&n,&m);
62     for (int i=1; i<=n; ++i) scanf("%d",&w[i]);
63     for (int i=1; i<=n; ++i) scanf("%d",&v[i]);
64     for (int i=1; i<=n; ++i) 
65     {
66         scanf("%d",&d[i]);
67         if (d[i]) add(d[i],i);
68     }
69     for (int i=1; i<=n; ++i)
70         if (!Dfn[i]) Tarjan(i);
71     
72     memset(head,0,sizeof(head)); num_edge=0;
73     for (int i=1; i<=n; ++i)
74         if (d[i] && Col[i]!=Col[d[i]])
75             add(Col[d[i]],Col[i]),Ind[Col[i]]++;
76     for (int i=1; i<=col_num; ++i)
77         if (!Ind[i]) add(col_num+1,i);
78     DP(col_num+1);
79     printf("%d\n",f[col_num+1][m]);
80 }

 

posted @ 2018-09-08 16:40  Refun  阅读(139)  评论(0编辑  收藏  举报