1. 程式人生 > >[BZOJ2427][HAOI2010]軟件安裝(Tarjan+DP)

[BZOJ2427][HAOI2010]軟件安裝(Tarjan+DP)

href 方便 stat output sta earch 磁盤容量 .com AR

2427: [HAOI2010]軟件安裝

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1987 Solved: 791
[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

Source

Day2

這麽簡單的題竟然做了三個小時?

環套樹DP,為了方便直接Tarjan縮點然後跑樹形DP即可。至於多叉樹轉二叉樹這個方法完全不需要用上,直接做樹上背包即可。

註意:除非卡常時,不要再用~i表示i>=0了,這樣無法處理i<0的情況。

堅決避免低級錯誤!

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5
#define For(i,x) for (int i=h[x]; i; i=nxt[i]) 6 using namespace std; 7 8 const int N=2100; 9 int n,m,scc,cnt,tim,top,h[N<<1],ind[N],w[N],v[N],d[N],wei[N],val[N]; 10 int bel[N],dp[N][N],stk[N],inq[N],dfn[N],low[N],to[N<<2],nxt[N<<2]; 11 12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 13 14 void tarjan(int x){ 15 low[x]=dfn[x]=++tim; inq[x]=1; stk[++top]=x; 16 For(i,x){ 17 int k=to[i]; 18 if (!dfn[k]) tarjan(k),low[x]=min(low[x],low[k]); 19 else if (inq[k]) low[x]=min(low[x],dfn[k]); 20 } 21 if (dfn[x]==low[x]){ 22 int t; scc++; 23 do{ t=stk[top--]; inq[t]=0; bel[t]=scc; }while (t!=x); 24 } 25 } 26 27 void dfs(int x){ 28 rep(i,wei[x],m) dp[x][i]=val[x]; 29 For(i,x){ 30 int k=to[i]; dfs(k); 31 for (int j=m-wei[x]; j>=0; j--) 32 rep(q,0,j) 33 dp[x][j+wei[x]]=max(dp[x][j+wei[x]],dp[x][j+wei[x]-q]+dp[k][q]); 34 } 35 } 36 37 int main(){ 38 scanf("%d%d",&n,&m); scc=n; 39 rep(i,1,n) scanf("%d",&w[i]); 40 rep(i,1,n) scanf("%d",&v[i]); 41 rep(i,1,n) { scanf("%d",&d[i]); if (d[i]) add(d[i],i); } 42 rep(i,1,n) if (!dfn[i]) tarjan(i); 43 rep(i,1,n){ 44 wei[bel[i]]+=w[i]; val[bel[i]]+=v[i]; 45 if (bel[i]!=bel[d[i]] && d[i]) add(bel[d[i]],bel[i]),ind[bel[i]]++; 46 } 47 rep(i,n+1,scc) if (!ind[i]) add(scc+1,i); 48 dfs(scc+1); printf("%d\n",dp[scc+1][m]); 49 return 0; 50 }

[BZOJ2427][HAOI2010]軟件安裝(Tarjan+DP)