要求方案的最大值
思路:先进行缩点,从新建图后强制让每隔点当根节点再进行树形dp
约定f[u][i]为u为根节点所消耗为i时的最大价值,遍历每一个相连的点,就可以推出
f[u][i]=max(f[u][i],f[u][i-j]+f[v][j])
细节:注意答案f[0][m](当一个超级源为根时的最大值
CODE
#include<bits/stdc++.h>
#define re register
#define ll long long
#define inl inline
using namespace std;
const int N=110;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return sum*f;
}
struct node{
int from,to,nxt;
}e[N],r[N];
int n,m,w[N],v[N],dfn[N],low[N],cnt1,cnt2,dep,top;
int stk[N],col[N],color,ind[N],f[N][1000],cost[N];
int head[N][2],val[N];
inl void add1(int u,int v){
e[++cnt1].from=u;
e[cnt1].to=v;
e[cnt1].nxt=head[u][0];
head[u][0]=cnt1;
}
inl void add2(int u,int v){
r[++cnt2].from=u;
r[cnt2].to=v;
r[cnt2].nxt=head[u][1];
head[u][1]=cnt2;
}
inl void tarjan(int u){
dfn[u]=low[u]=++dep,stk[++top]=u;
for(re int i=head[u][0];i;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!col[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
color++;
do{
col[stk[top]]=color;
cost[color]+=w[stk[top]];
val[color]+=v[stk[top]];
top--;
}while(stk[top+1]!=u);
}
}
inl void dp(int u){
for(re int i=cost[u];i<=m;i++) f[u][i]=val[u];
for(re int i=head[u][1];i;i=r[i].nxt){
int v=r[i].to;
dp(v);
for(int i=m-cost[u];i>=0;i--){
for(int j=0;j<=i;j++){
f[u][i+cost[u]]=max(f[u][i+cost[u]],f[u][i+cost[u]-j]+f[v][j]);
}
}
}
}
int main(){
n=read(),m=read();
for(re int i=1;i<=n;i++) w[i]=read();
for(re int i=1;i<=n;i++) v[i]=read();
for(int i=1;i<=n;i++){
int x=read();add1(x,i);
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=cnt1;i++){
int u=e[i].from,v=e[i].to;
if(col[u]!=col[v]) add2(col[u],col[v]),ind[col[v]]=1;
}
for(int i=1;i<=color;i++) if(!ind[i]) add2(0,i);
dp(0);
printf("%d\n",f[0][m]);
}