emmm一眼望过去,觉得是树形dp,但是只有40分,然后突然看到间接依赖也可以,emmmm,也就是说,如果一些物品的依赖关系是一个环,那么这个环可以选,也可以全不选。。。坑爹。
所以我们要把这个环内的东西累加到一个点上,这是啥?强联通缩点啊,先跑tarjan,然后把一个环内的物品累加到一起,放在新树上,然后你以为自己能A了?不,你还是40,为啥呢?因为你都知道有环了,那么肯定有环的时候,0号点不会被依赖,你会输出0,那就把所有点连到0吧!然后你就连40都没了。因为可能有一开始连着的,你给人家连了两遍,怎么办呢?构建新图时,记录与0连接的点,然后下面判断哪个环没有与0相连,连上就好,然后这道题就被解决啦
代码
//By AcerMo
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=550;
int n,m;
int dp[250][605];
stack<int>s;
vector<int>v[1000];
vector<int>G[M*2];
int c[550],w[550];
int c1[M],w1[M];
bool jud[M];
inline int read()
{
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void tdp(int x)
{
for (int i=w1[x];i<=m;i++) dp[x][i]=c1[x];
for (int i=0;i<G[x].size();i++)
{
int to=G[x][i];tdp(to);
for (int k=m;k>=w1[x];k--)
for (int j=k-w1[x];j>=w1[to];j--)
dp[x][k]=max(dp[x][k],dp[x][k-j]+dp[to][j]);
}
return ;
}//裸的树形背包
int low[M],dfn[M],ind,ti,fa[M],vis[M];
inline void tarjan(int x)
{
low[x]=dfn[x]=++ind;vis[x]=1;s.push(x);
for (int i=0;i<v[x].size();i++)
{
int go=v[x][i];
if (!dfn[go])
{
tarjan(go);
low[x]=min(low[x],low[go]);
}
else if (vis[go])
low[x]=min(low[x],dfn[go]);
}
if (low[x]==dfn[x])
{
ti++;int u=-1;
while (u!=x)
{
u=s.top();s.pop();
vis[u]=0;fa[u]=ti;
}
}
return ;
}//tarjan缩点
int main()
{
n=read();m=read();int f;
for (int i=1;i<=n;i++) w[i]=read();
for (int i=1;i<=n;i++) c[i]=read();
for (int i=1;i<=n;i++) f=read(),v[f].push_back(i);//原图
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i);//tarjan
for (int i=1;i<=n;i++)
c1[fa[i]]+=c[i],w1[fa[i]]+=w[i];//累加到环父节点
for (int i=0;i<=n;i++)
for (int k=0;k<v[i].size();k++)
if (fa[i]!=fa[v[i][k]]) G[fa[i]].push_back(fa[v[i][k]]),jud[fa[v[i][k]]]=1;//构造新图
for (int i=1;i<=ti;i++)
if (!jud[i]) G[0].push_back(i);//看看哪个没连着
tdp(0);cout<<dp[0][m];//正常操作
return 0;
}