现在我们的手头有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 )
一个整数,代表最大价值。
软件之间的关系构成树或环,暴力把环缩成一点然后就是树形背包了。
#include<cstdio>
#include<vector>
std::vector<int> ss[128];
int pa[128];
int id[128];
int w[128],v[128],fa;
int n,m;
int f[128][512];
int g[128][512];
void maxs(int&a,int b){
if(a<b)a=b;
}
int t=0;
void dfs(int x){
int sz=ss[x].size();
if(sz){
for(int i=0;i<sz;i++)dfs(ss[x][i]);
int u=ss[x][0];
for(int j=m;j>=0;j--)g[x][j]=f[u][j];
for(int i=1;i<sz;i++){
u=ss[x][i];
for(int j=m;j>=0;j--)
for(int k=0;k<=j;k++)
maxs(g[x][j],g[x][j-k]+f[u][k]);
}
for(int j=w[x];j<=m;j++)
f[x][j]=g[x][j-w[x]]+v[x];
}else{
for(int i=w[x];i<=m;i++)f[x][i]=v[x];
}
}
int 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",&fa);
if(i!=fa)pa[i]=fa;
id[i]=i;
}
for(int i=1;i<=n;i++){
int a=i;
if(~pa[i])
for(int j=1;j<=110;j++){
a=pa[a];
if(a<1)break;
if(a==i){
for(a=pa[a];a!=i&&~a;a=fa){
v[i]+=v[a];
w[i]+=w[a];
fa=pa[a];
pa[a]=-1;
id[a]=i;
}
pa[i]=0;
break;
}
}
}
for(int i=1;i<=n;i++){
if(~pa[i])ss[id[pa[i]]].push_back(i);
}
dfs(0);
printf("%d",f[0][m]);
return 0;
}