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

[HAOI2010]軟件安裝

dfs while bool hit ott 計算機 code data- ack

題目描述

現在我們的手頭有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,從iDi建一條有向邊。

在這裏我們發現,依賴關系可以形成環。對於一個環,裏面的節點要麽都選,要麽都不選。

所以,這裏先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 }

[HAOI2010]軟件安裝