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