题目描述
现在我们的手头有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
缩点后树形dp
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1007; inline int read() { int x=0,f=1; char c=getchar() ; while(c<'0'||c>'9'){ if(c=='-')f=-1;c=getchar();}; while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar(); return x*f; } int w[maxn],v[maxn],n,m; struct node { int v,next; }edge[maxn*5],E[maxn*10]; int num=0,N=0,H[maxn*2],head[maxn]; inline void add_edge(int u,int v) { edge[++num].v=v;edge[num].next=head[u];head[u]=num; } inline void ADD(int u,int v) { E[++N].v=v;E[N].next=H[u];H[u]=N; } int dfn[maxn],low[maxn],color[maxn],color_cnt=0,stack[maxn],vul[maxn],wul[maxn]; bool vis[maxn];int top; void tarjan(int x) { dfn[x]=low[x]=++num; vis[x]=1;stack[++top]=x; for(int i=head[x];i;i=edge[i].next) { int v=edge[i].v; if(!dfn[v]) { tarjan(v); low[x]=std::min(low[x],low[v]); } else if(vis[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { color_cnt++; while(stack[top+1]!=x) { vis[stack[top]]=0; color[stack[top]]=color_cnt; vul[color_cnt]+=v[stack[top]]; wul[color_cnt]+=w[stack[top]];top--; } } } int dp[maxn*2][maxn*5]; void dfs(int x) { for(int i=wul[x];i<=m;++i) dp[x][i]=vul[x]; for(int i=H[x];i;i=E[i].next) { int vv=E[i].v; dfs(vv); for(int j=m-wul[x];j>=0;j--) for(int k=0;k<=j;k++) { dp[x][j+wul[x]]=max(dp[x][j+wul[x]],dp[x][j+wul[x]-k]+dp[vv][k]); } } //for(int i=m;i>=0;i--) //if(w[i]<=i)dp[x][i]=v[x]; //else dp[x][i]=0; } bool rd[maxn*2]; int main() { n=read(),m=read(); for(int i=1;i<=n;++i) w[i]=read(); for(int i=1;i<=n;++i) v[i]=read(); for(int a,i=1;i<=n;++i) { a=read(); if(a) add_edge(a,i); }num=0; //for(int i=1;i<=n;++i) { // color[i]=i; //} for(int i=1;i<=n;++i) if(!dfn[i])tarjan(i); for(int i=1;i<=n;++i) for(int j=head[i];j;j=edge[j].next) { int vv=edge[j].v; if(color[i]!=color[vv]) { ADD(color[i],color[vv]); rd[color[vv]]=1; } } for(int i=1;i<=n;++i) { if(!rd[color[i]])ADD(0,color[i]); } dfs(0); printf("%d ",dp[0][m]); return 0; }