连接:点击打开链接
因为可能有环,即要么一起选,要么都不选,做一期强联通缩点,在树上dp即可。
注意,每个点做完要延父亲边更新一次。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int w[210],v[210],d[210],f[510][210],g[210],n,m;
int dfn[110],low[110],id,top,sta[110],belong[110],cnt=0;
bool u[110];
struct node{
int y,next;
}a[210];int last[210],len=0;
void ins(int x,int y)
{
a[++len].y=y;
a[len].next=last[x];last[x]=len;
}
void dp(int x)
{
g[x]=g[d[x]]+w[x];
for(int i=m;i>=g[x];i--)
f[i][x]=max(f[i][x],f[i-w[x]][d[x]]+v[x]);
for(int i=last[x];i;i=a[i].next) dp(a[i].y);
int fa=d[x];
while(1)
{
for(int i=0;i<=m;i++) f[i][fa]=max(f[i][fa],f[i][x]);
if(fa==0) break;
fa=d[fa];
}
}
void dfs(int x)
{
dfn[x]=low[x]=++id;
sta[++top]=x;u[x]=true;
if(d[x]!=0)
{
int y=d[x];
if(dfn[y]==-1)
{
dfs(y);
low[x]=min(low[x],low[y]);
}
else
if(u[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
cnt++;int i;
do
{
i=sta[top--];
w[cnt]+=w[i];v[cnt]+=v[i];
u[i]=false;
belong[i]=cnt;
}while(i!=x);
}
}
int main()
{
scanf("%d %d",&n,&m);cnt=n;
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",&d[i]);
memset(dfn,-1,sizeof(dfn));
memset(u,false,sizeof(u));id=top=0;
for(int i=1;i<=n;i++)
if(dfn[i]==-1) dfs(i);
for(int i=1;i<=n;i++)
{
if(belong[i]!=belong[d[i]])
d[belong[i]]=belong[d[i]],ins(belong[d[i]],belong[i]);
}
for(int i=n+1;i<=cnt;i++) if(d[i]==0) dp(i);
printf("%d",f[m][0]);
}