bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp
[HAOI2010]软件安装
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
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 }