每个人都至多有一个依赖点 所以有可能成环 先tarjan缩点并处理出环的信息wei va
再将缩点后的图重新连接 将入度为0的点和0点连接 这样就构成了一颗树
由此做树形dp 只有父亲节点选了它的儿子才能选 所以在访问进去时先把wei[u]~m都赋为va[u] 我会说我又因为树形dp卡了半天吗
#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
const int N=100+5,M=500+5,inf=0x3f3f3f3f,P=19650827;
int n,m,in[N],w[N],val[N],f[N][M];
template <class t>void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
int head[N],tot=0;
struct edge{int u,v,nxt;}e[N],E[N];
void add(int u,int v){
e[++tot]=(edge){u,v,head[u]},head[u]=tot;
}
int idx=0,Bcnt=0,dfn[N],bl[N],low[N],wei[N],va[N];
stack<int>s;bool inst[N];
void tarjan(int u){
dfn[u]=low[u]=++idx;
s.push(u),inst[u]=1;
for(int i=head[u],v;i;i=e[i].nxt){
v=e[i].v;
if(!dfn[v]) tarjan(v),low[u]=Min(low[u],low[v]);
else if(inst[v]&&dfn[v]<low[u]) low[u]=dfn[v];
}
if(low[u]==dfn[u]){
int v;++Bcnt;
do{
v=s.top(),s.pop();
inst[v]=0,bl[v]=Bcnt,wei[Bcnt]+=w[v],va[Bcnt]+=val[v];
}while(u!=v);
}
}
int hd[N],tt=0;
void Add(int u,int v){
E[++tt]=(edge){u,v,hd[u]},hd[u]=tt;
}
void dfs(int u){
for(int i=wei[u];i<=m;++i) f[u][i]=va[u];
for(int i=hd[u],v;i;i=E[i].nxt){
v=E[i].v,dfs(v);
for(int j=m-wei[u];j>0;--j)
for(int k=0;k<=j;++k)
f[u][j+wei[u]]=Max(f[u][j+wei[u]],f[u][j+wei[u]-k]+f[v][k]);
}
}
int main(){
// freopen("in2.txt","r",stdin);
//freopen("xor.out","w",stdout);
rd(n),rd(m);
for(int i=1;i<=n;++i) rd(w[i]);
for(int i=1;i<=n;++i) rd(val[i]);
for(int i=1,u;i<=n;++i){
rd(u);
if(u) add(u,i);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=tot;++i)
if(bl[e[i].u]!=bl[e[i].v]) Add(bl[e[i].u],bl[e[i].v]),++in[bl[e[i].v]];
for(int i=1;i<=Bcnt;++i) if(!in[i]) Add(0,i);
memset(f,0,sizeof(f));dfs(0);
printf("%d",f[0][m]);
return 0;
}