题解:
如果是一个环,那么就是每个点都要
否则就是一个数
然后dp
tarjan强连通+树形dp
代码:
#include<bits/stdc++.h> using namespace std; const int N=1005; int n,m,cnt,last[N],x,last2[N],inq[N],scc,ind,top,v[N]; int w[N],sv[N],sw[N],dfn[N],low[N],belong[N],q[N],f[N][N],in[N]; struct edge { int to,next; }e[N],ed[N]; void jb(int u,int v) { e[++cnt].to=v; e[cnt].next=last[u]; last[u]=cnt; } void jb2(int u,int v) { in[v]=1; ed[++cnt].to=v; ed[cnt].next=last2[u]; last2[u]=cnt; } void tarjan(int x) { int now=0; low[x]=dfn[x]=++ind; q[++top]=x;inq[x]=1; for (int i=last[x];i;i=e[i].next) if (!dfn[e[i].to]) { tarjan(e[i].to); low[x]=min(low[x],low[e[i].to]); } else if(inq[e[i].to]) low[x]=min(low[x],dfn[e[i].to]); if (low[x]==dfn[x]) { scc++; while (now!=x) { now=q[top--];inq[now]=0; belong[now]=scc; sv[scc]+=v[now]; sw[scc]+=w[now]; } } } void rebuild() { cnt=0; for (int x=1;x<=n;x++) for (int i=last[x];i;i=e[i].next) if (belong[e[i].to]!=belong[x]) jb2(belong[x],belong[e[i].to]); } void dp(int x) { for (int i=last2[x];i;i=ed[i].next) { dp(ed[i].to); for (int j=m-sw[x];j>=0;j--) for (int k=0;k<=j;k++) f[x][j]=max(f[x][j],f[x][k]+f[ed[i].to][j-k]); } for (int j=m;j>=0;j--) if (j>=sw[x])f[x][j]=f[x][j-sw[x]]+sv[x]; else f[x][j]=0; } 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",&x); if (x)jb(x,i); } for (int i=1;i<=n;i++) if (!dfn[i])tarjan(i); rebuild(); for (int i=1;i<=scc;i++) if (!in[i])jb2(scc+1,i); dp(scc+1); printf("%d\n",f[scc+1][m]); return 0; }