首先tarjan缩点应该能看出来,然后我用topsort跑了个DAG上的一维dp,结果WA的很惨。
其实用DAG应该也能做,但是DAG强调整体顺序,而对一些局部问题,例如两个儿子怎么分配,是否给当前节点分配,那就太粗略化了,导致错误。
正确的姿势是把所有没有入度的点接到虚根上,因为tarjan缩完很可能是个森林,剩下的就是跑树形依赖的背包了。

#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<vector> #include<queue> #include<set> #include<map> using namespace std; struct EDGE{ int ed,nex; }edge[200],edgec[200];int num,numc,first[200],firstc[200]; int read(){ int sum=0,f=1;char x=getchar(); while(x<'0'||x>'9'){ if(x=='-') f=-1; x=getchar(); }while(x>='0'&&x<='9'){ sum=sum*10+x-'0'; x=getchar(); }return sum*f; } int n,m,w[200],v[200],dp[200][2000]; int dfn[200],low[200],ord; int stack[200000],top,ans,root; int sccnum,bl[200]; vector<int>scc[200]; int wc[200],vc[200],du[200]; bool ins[200]; void add(int st,int ed){ edge[++num].ed=ed; edge[num].nex=first[st]; first[st]=num; } void addc(int st,int ed){ edgec[++numc].ed=ed; edgec[numc].nex=firstc[st]; firstc[st]=numc; } void tarjan(int x){ dfn[x]=low[x]=++ord; stack[++top]=x;ins[x]=1; for(int i=first[x];i;i=edge[i].nex){ int y=edge[i].ed; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); }else if(ins[y]) low[x]=min(low[x],dfn[y]); }if(low[x]==dfn[x]){ sccnum++;int p; do{ p=stack[top--];ins[p]=0; bl[p]=sccnum;scc[sccnum].push_back(p); }while(x!=p); } } void dfs(int x){ //cout<<"fa="<<x<<endl; /* for(int i=firstc[x];i;i=edgec[i].nex){ int y=edgec[i].ed; cout<<y<<" "; }*/ for(int i=firstc[x];i;i=edgec[i].nex){ int y=edgec[i].ed; dfs(y); for(int j=m-wc[x];j>=0;j--) for(int k=0;k<=j;k++) dp[x][j]=max(dp[x][j],dp[x][k]+dp[y][j-k]); } for(int i=m;i>=wc[x];i--) dp[x][i]=dp[x][i-wc[x]]+vc[x]; for(int i=0;i<wc[x];i++) dp[x][i]=0; } int main(){ /*freopen("9.in","r",stdin); freopen("9.out","w",stdout);*/ /* memset(dp,0xcf,sizeof(dp)); dp[0]=0;*/ 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 i=1,D;i<=n;i++){ D=read(); if(!D) continue; add(D,i); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=sccnum;i++) for(int j=0;j<scc[i].size();j++) wc[i]+=w[scc[i][j]],vc[i]+=v[scc[i][j]]; for(int i=1;i<=n;i++){ for(int j=first[i];j;j=edge[j].nex){ int y=edge[j].ed; if(bl[i]==bl[y]) continue; addc(bl[i],bl[y]); // cout<<"St="<<bl[i]<<" Ed="<<bl[y]<<endl; du[bl[y]]++; } } root=sccnum+1; for(int i=1;i<=sccnum;i++) if(!du[i]) addc(root,i); /* for(int i=1;i<=numc;i++) cout<<edgec[i].ed<<" "<<edgec[i].nex<<endl;*/ /* for(int i=1;i<=sccnum;i++){ for(int j=0;j<scc[i].size();j++) cout<<scc[i][j]<<" "; cout<<endl; } for(int i=1;i<=sccnum;i++) cout<<wc[i]<<" "<<vc[i]<<endl;*/ /* for(int i=1;i<=n;i++) cout<<bl[i]<<" ";cout<<endl; for(int i=1;i<=sccnum;i++) cout<<wc[i]<<" "<<vc[i]<<endl; for(int i=1;i<=numc;i++) cout<<edgec[i].st<<" "<<edgec[i].ed<<endl;*/ dfs(root); /* for(int i=0;i<=m;i++) cout<<dp[root][i]<<" ";cout<<endl;*/ printf("%d",dp[root][m]);cout<<endl; return 0; }