1. 程式人生 > >bzoj 2427 [HAOI2010]軟件安裝 Tarjan縮點+樹形dp

bzoj 2427 [HAOI2010]軟件安裝 Tarjan縮點+樹形dp

code nbsp std div getchar 間接 情況 insert 工作

[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 }

bzoj 2427 [HAOI2010]軟件安裝 Tarjan縮點+樹形dp