[HAOI2010]软件安装
题目描述
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
输入输出格式
输入格式:
第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 )
输出格式:
一个整数,代表最大价值
输入输出样例
输入样例#1:
3 10 5 5 6 2 3 4 0 1 1
输出样例#1:
5
首先对于每个i,从i向Di建一条有向边。
在这里我们发现,依赖关系可以形成环。对于一个环,里面的节点要么都选,要么都不选。
所以,这里先Tarjan强连通分量缩点,构成一个新图,这样新图里的每个节点可以看成一个整体考虑
然后就变成裸的树形dp
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Messi 7 { 8 int next,to; 9 }edge[10001],edge2[10001]; 10 int head[10001],num,low[10001],dfn[10001],dfscnt,stack[10001],inStack[10001]; 11 int n,m,scnt,top,sccno[10001]; 12 int ans,num2,head2[10001],w[10001]; 13 int v[10001],V[10001],W[10001],f[501][1001]; 14 bool b[1001]; 15 void add(int u,int v) 16 { 17 num++; 18 edge[num].next=head[u]; 19 edge[num].to=v; 20 head[u]=num; 21 } 22 void add2(int u,int v) 23 { 24 num2++; 25 edge2[num2].next=head2[u]; 26 edge2[num2].to=v; 27 head2[u]=num2; 28 } 29 void dfs(int u) 30 {int i,j; 31 low[u]=dfn[u]=++dfscnt; 32 stack[++top]=u; 33 inStack[u]=1; 34 for (i=head[u];i;i=edge[i].next) 35 { 36 int v=edge[i].to; 37 if (dfn[v]==0) 38 { 39 dfs(v); 40 low[u]=min(low[u],low[v]); 41 }else if (inStack[v]) low[u]=min(low[u],dfn[v]); 42 } 43 if (dfn[u]==low[u]) 44 { 45 ++scnt; 46 while (top&&stack[top+1]!=u) 47 { 48 sccno[stack[top]]=scnt; 49 inStack[stack[top--]]=0; 50 } 51 } 52 } 53 void dp(int x) 54 {int i,j,k; 55 for (i=head2[x];i;i=edge2[i].next) 56 { 57 int v=edge2[i].to; 58 dp(v); 59 for (j=m-V[x];j>=0;j--) 60 { 61 for (k=0;k<=j;k++) 62 f[x][j]=max(f[x][j],f[x][k]+f[v][j-k]); 63 } 64 } 65 for (j=m;j>=0;j--) 66 if (j-V[x]>=0) 67 f[x][j]=f[x][j-V[x]]+W[x]; 68 else f[x][j]=0; 69 } 70 int main() 71 {int i,x,j; 72 cin>>n>>m; 73 for (i=1;i<=n;i++) 74 scanf("%d",&v[i]); 75 for (i=1;i<=n;i++) 76 scanf("%d",&w[i]); 77 for (i=1;i<=n;i++) 78 { 79 scanf("%d",&x); 80 if (x) add(x,i); 81 } 82 for (i=1;i<=n;i++) 83 if (dfn[i]==0) dfs(i); 84 for (i=1;i<=n;i++) 85 { 86 int u=sccno[i]; 87 W[u]+=w[i]; 88 V[u]+=v[i]; 89 for (j=head[i];j;j=edge[j].next) 90 { 91 int v=sccno[edge[j].to]; 92 if (u!=v) b[v]=1,add2(u,v); 93 } 94 } 95 for (i=1;i<=scnt;i++) 96 { 97 if (b[i]==0) 98 add2(scnt+1,i); 99 } 100 dp(scnt+1); 101 cout<<f[scnt+1][m]; 102 }