1. 程式人生 > >[Bzoj 2427] [HAOI2010] 軟件安裝

[Bzoj 2427] [HAOI2010] 軟件安裝

不能 OS 問題 void mst pre pos IT ios

2427: [HAOI2010]軟件安裝

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

一個整數,代表最大價值。

Solution

觀察到,對於一個環上的一群節點,要麽都選,要麽都不選。(如果選部分不會發生價值,相當於白白浪費空間)

所以先 Tarjan 縮點,然後樹形 DP 即可。(我好菜啊還不會樹形 DP )

Code

// By YoungNeal
#include<cstdio> #include<iostream> using namespace std; int c[105]; bool in[105]; int deg[105]; int n,m,root; int cnt,sum,tot; int
f[105][505]; int stk[105],top; int low[105],dfn[105]; int head[105],head2[105]; int w[105],v[105],d[105]; int scc_w[105],scc_v[105]; struct Edge{ int to,nxt; }edge[10005],edge2[10005]; void add(int x,int y){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt; } void add_c(int x,int y){ edge2[++cnt].to=y; edge2[cnt].nxt=head2[x]; head2[x]=cnt; } void tarjan(int now){ dfn[now]=low[now]=++sum; stk[++top]=now;in[now]=1; for(int i=head[now];i;i=edge[i].nxt){ int to=edge[i].to; if(!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]); else if(in[to]) low[now]=min(low[now],low[to]); } if(dfn[now]==low[now]){ tot++;int y; do{ y=stk[top--]; c[y]=tot; in[y]=0; scc_w[tot]+=w[y]; scc_v[tot]+=v[y]; }while(y!=now); } } void dfs(int now){ for(int i=head2[now];i;i=edge2[i].nxt){ int to=edge2[i].to; dfs(to); for(int j=m;~j;j--){ for(int p=0;p<=j;p++) f[now][j]=max(f[now][j],f[to][p]+f[now][j-p]); } } for(int i=m;~i;i--){ if(i>=scc_w[now]) f[now][i]=f[now][i-scc_w[now]]+scc_v[now]; else f[now][i]=0; } } signed main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=n;i++) scanf("%d",&v[i]); for(int i=1;i<=n;i++) scanf("%d",&d[i]); for(int i=1;i<=n;i++){ if(!d[i]) continue; add(d[i],i); } cnt=0; for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } for(int i=1;i<=n;i++){ if(!d[i]) continue; if(c[i]==c[d[i]]) continue; add_c(c[d[i]],c[i]);deg[c[i]]++; } tot++; for(int i=1;i<tot;i++){ if(deg[i]) continue; add_c(tot,i); } dfs(tot); printf("%d\n",f[tot][m]); return 0; }

[Bzoj 2427] [HAOI2010] 軟件安裝