bzoj2427: [HAOI2010]软件安装

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

 
题解:
先tarjan缩下点,使其变成一棵树,然后我们就可以进行树上背包了
设f[u][i]表示选到u,用了空间i,得到的最大收益是多少
O(nm2)的转移显然,但其实可以优化到O(nm)
设u的一个儿子是v,则我们可以把f[u]作为初始状态直接付给f[v],然后就可以减少一个m的转移复杂度
注意把f[u]作为初始状态直接付给f[v]时,f[v]的第二维有下限(就是v及其所有祖先所占的空间和)
code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 char ch;
 8 bool ok;
 9 void read(int &x){
10     ok=0;
11     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
12     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
13     if (ok) x=-x;
14 }
15 const int maxn=105;
16 const int maxm=505;
17 const int inf=1010580541;
18 int n,m,a[maxn],b[maxn],x,ans;
19 int f[maxn][maxm],g[maxm];
20 int idx,dfn[maxn],low[maxn],stack[maxn],top,cnt,bel[maxn],siz[maxn],val[maxn],deg[maxn];
21 bool in[maxn],bo[maxn];
22 struct Graph{
23     int tot,now[maxn],son[maxn],pre[maxn];
24     void put(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
25     void dfs(int u){
26         dfn[u]=low[u]=++idx,stack[++top]=u,in[u]=1;
27         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
28             if (!dfn[v]) dfs(v),low[u]=min(low[u],low[v]);
29             else if (in[v]) low[u]=min(low[u],dfn[v]);
30         if (dfn[u]==low[u]){
31             int v; ++cnt;
32             do{v=stack[top--],bel[v]=cnt,siz[cnt]+=a[v],val[cnt]+=b[v],in[v]=0;}while (u!=v);
33         }
34     }
35     /*void dp(int u){
36         bo[u]=1;
37         memset(f[u],195,sizeof(f[u]));
38         f[u][siz[u]]=val[u];
39         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (!bo[v]){
40             dp(v);
41             memcpy(g,f[u],sizeof(g));
42             for (int i=0;i<=m;i++) for (int j=m;j>=i;j--) g[j]=max(g[j],f[v][i]+f[u][j-i]);
43             memcpy(f[u],g,sizeof(g));
44         }
45         f[u][0]=max(f[u][0],0);
46     }*/
47     /*void dp(int u,int m){
48         //cout<<u<<' '<<m<<endl;
49         bo[u]=1;
50         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (!bo[v]){
51             for (int i=0;i<=m;i++) f[v][i]=f[u][i];
52             dp(v,m-siz[v]);
53             for (int i=siz[v];i<=m;i++) f[u][i]=max(f[u][i],f[v][i-siz[v]]+val[v]);
54         }
55     }*/
56     void dp(int u,int low){
57         bo[u]=1;
58         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (!bo[v]){
59             for (int i=low;i<=m-siz[v];i++) f[v][i+siz[v]]=f[u][i]+val[v];
60             dp(v,low+siz[v]);
61             for (int i=low+siz[v];i<=m;i++) f[u][i]=max(f[u][i],f[v][i]);
62         }
63     }
64 }G1,G2;
65 int main(){
66     read(n),read(m);
67     for (int i=1;i<=n;i++) read(a[i]);
68     for (int i=1;i<=n;i++) read(b[i]);
69     for (int i=1;i<=n;i++) read(x),G1.put(x,i);
70     for (int i=0;i<=n;i++) if (!dfn[i]) G1.dfs(i);
71     for (int u=0;u<=n;u++) for (int p=G1.now[u],v=G1.son[p];p;p=G1.pre[p],v=G1.son[p])
72         if (bel[u]!=bel[v]) G2.put(bel[u],bel[v]),deg[bel[v]]++;
73     for (int u=1;u<=n;u++) if (!deg[bel[u]]) G2.put(bel[0],bel[u]);
74     //G2.dp(bel[0]);
75     //G2.dp(bel[0],m);
76     G2.dp(bel[0],0);
77     for (int i=0;i<=m;i++) ans=max(ans,f[bel[0]][i]);
78     printf("%d\n",ans);
79     return 0;
80 }

 

posted @ 2016-05-16 21:51 chenyushuo 阅读(...) 评论(...) 编辑 收藏