题目描述
现在我们的手头有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
拿到这个题,我们先要对其进行tarjan缩点。为什么要tarjan缩点??因为如果图中出现了一个环这说明这些软件必须一起将这些软件一块放入,这样我们可以将这样的一个环直接看成一个软件,这个软件的价值与体积即为环内点的总价值、体积。这样的话我们直接对原图进行tarjan缩点然后再在新图上乱搞就好了、、、
我们可以发现我们缩完点后的新图是不是可能由若干个树组成,这样处理起来无疑是很麻烦的。因此我们要将这个图给连起来(怎么连??我们建一个原点,然后向缩完点后的每一棵树的树根连边),形成一棵树,然后我们在这棵树上跑树形dp就可以啦。
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 1100 using namespace std; bool vis[N],vist[N]; int n,m,y,tim,top,tot,tat,sum,ans; int v[N],w[N],zv[N],zw[N],stack[N],low[N]; int dad[N],dfn[N],head[N],head1[N],belong[N],f[N][N]; struct Edge { int to,from,next; }edge[N],edge1[N]; int add(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot; } int add1(int x,int y) { tat++; edge1[tat].to=y; edge1[tat].next=head1[x]; head1[x]=tat; } int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int tarjan(int now) { dfn[now]=low[now]=++tim; vis[now]=true,stack[++top]=now; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(vis[t]) low[now]=min(low[now],dfn[t]); else if(!dfn[t]) tarjan(t),low[now]=min(low[now],low[t]); } if(dfn[now]==low[now]) { sum++;belong[now]=sum; zw[sum]+=w[now],zv[sum]+=v[now]; for(;stack[top]!=now;top--) { int x=stack[top]; belong[x]=sum,vis[x]=false; zw[sum]+=w[x],zv[sum]+=v[x]; } vis[now]=false; top--; } } int shink_point() { for(int i=1;i<=n;i++) for(int j=head[i];j;j=edge[j].next) if(belong[i]!=belong[edge[j].to]) { dad[belong[edge[j].to]]=belong[i]; add1(belong[i],belong[edge[j].to]); } } int dfs(int x) { for(int i=head1[x];i;i=edge1[i].next) { int t=edge1[i].to; dfs(t); for(int j=m-zv[x];j>0;j--) for(int k=0;k<=j;k++) f[x][j]=max(f[x][j],f[x][k]+f[t][j-k]); } for(int i=m;i>=0;i--) if(i>=zv[x]) f[x][i]=f[x][i-zv[x]]+zw[x]; else f[x][i]=0; } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) v[i]=read(); for(int i=1;i<=n;i++) w[i]=read(); for(int i=1;i<=n;i++) { y=read(); if(y==0) continue; add(y,i); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); shink_point(); for(int i=1;i<=sum;i++) if(!dad[i]) add1(sum+1,i); dfs(sum+1); ans=f[sum+1][m]; printf("%d",ans); return 0; }