题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2427
先用Tarjan算法缩一次强连通分量,然后建树,DP就可以了。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
#define MAXN 110
#define MAXM 510
struct edge {
int t;
edge *next;
edge () {
next=NULL;
}
} *head[MAXN];
void AddEdge(int s,int t) {
edge *p=new(edge);
p->t=t,p->next=head[s];
head[s]=p;
}
int n,m;
int V[MAXN],w[MAXN],d[MAXN];
int dfn[MAXN],low[MAXN],Index=0,scc[MAXN];
bool f[MAXN];
stack<int>S;
void Tarjan(int v) {
dfn[v]=low[v]=++Index;
f[v]=true;
S.push(v);
for (edge *p=head[v];p;p=p->next) {
if (!dfn[p->t]) {
Tarjan(p->t);
low[v]=min(low[v],low[p->t]);
} else if (f[p->t]) low[v]=min(low[v],low[p->t]);
}
if (dfn[v]==low[v]) {
int u;
do {
u=S.top();
S.pop();
f[u]=false;
scc[u]=v;
} while (u!=v);
}
}
int dp[MAXN][MAXM][2];
void Dp(int v) {
int k=0;
dp[v][V[v]][0]=w[v];
for (edge *p=head[v];p;p=p->next) {
Dp(p->t);
for (int j=0;j<=m;j++) dp[v][j][k^1]=dp[v][j][k];
for (int i=0;i<=m-V[v];i++) if (dp[p->t][i][1]) {
for (int j=V[v];j<=m-i;j++) {
dp[v][j+i][k^1]=max(dp[v][j+i][k^1],dp[v][j][k]+dp[p->t][i][1]);
}
}
k^=1;
}
for (int i=0;i<=m;i++) dp[v][i][1]=dp[v][i][k];
}
int main() {
memset(head,0,sizeof(head));
cin>>n>>m;
for (int i=0;i++<n;) cin>>V[i];
for (int i=0;i++<n;) cin>>w[i];
for (int i=0;i++<n;) {
cin>>d[i];
if (d[i])AddEdge(i,d[i]);
}
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
for (int i=0;i++<n;) if (!dfn[i]) {
Tarjan(i);
}
for (int i=0;i++<n;) if (scc[i]!=i) {
w[scc[i]]+=w[i],V[scc[i]]+=V[i];
}
memset(head,0,sizeof(head));
for (int i=0;i++<n;) {
if (scc[i]==i) {
if (scc[d[i]]==i)AddEdge(0,i);
else AddEdge(scc[d[i]],i);
}
}
memset(dp,0,sizeof(dp));
V[0]=w[0]=0;
Dp(0);
int ans=0;
for (int i=0;i<=m;i++) ans=max(dp[0][i][1],ans);
cout<<ans<<endl;
return 0;
}