今天复习了一下强连通分量(显然之前就没学得好)。
强连通分量一般用在环套树的有向图中,先把每个强连通分量缩点,然后把它当做普通树处理。
双联通分量也顺便看了一下,但是感觉用处远远没有强连通分量大啊。
借这道题来纪念一下强连通分量,希望以后有用上的时候。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
const int maxn=105,maxm=505,inf=0x3f3f3f3f;
int n,m,dp[maxn][maxm];
int cost[maxn],val[maxn],tmp_w[maxn],tmp_v[maxn];
int scc_num[maxn],scc_cnt,deg[maxn];
int dfn[maxn],low[maxn],dfs_clock;
struct qxx{
int Begin[maxn],Next[maxn],to[maxn],e;
void init(){
memset(Begin,0,sizeof(Begin)),e=0;
}
void add(int u,int v){
to[++e]=v,Next[e]=Begin[u],Begin[u]=e;
}
}E,G;
stack<int>S;
void dfs(int u){
S.push(u);
low[u]=dfn[u]=++dfs_clock;
for(int i=E.Begin[u];i;i=E.Next[i]){
int v=E.to[i];
if(!dfn[v]){
dfs(v);
low[u]=min(low[u],low[v]);
}else if(!scc_num[v])
low[u]=min(low[u],low[v]);
}if(low[u]==dfn[u]){
scc_num[u]=++scc_cnt;
cost[scc_cnt]=tmp_w[u];
val[scc_cnt]=tmp_v[u];
while(S.top()!=u){
cost[scc_cnt]+=tmp_w[S.top()];
val[scc_cnt]+=tmp_v[S.top()];
scc_num[S.top()]=scc_cnt,S.pop();
}S.pop();
}
}
bool vis[maxn];
void dfs_dp(int u){
vis[u]=1;
for(int j=0;j<cost[u];j++)dp[u][j]=-inf;
for(int j=cost[u];j<=m;j++)dp[u][j]=val[u];
for(int i=G.Begin[u];i;i=G.Next[i]){
int v=G.to[i];
if(vis[v])continue;
dfs_dp(v);
for(int j=m;j>=cost[u];j--)
for(int k=j-cost[u];k>=cost[v];k--)
dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
}
}
int main(){
int k;
scanf("%d%d",&n,&m);
E.init(),G.init();
for(int i=1;i<=n;i++)
scanf("%d",&tmp_w[i]);
for(int i=1;i<=n;i++)
scanf("%d",&tmp_v[i]);
for(int i=1;i<=n;i++){
scanf("%d",&k);
if(k)E.add(k,i);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
for(int i=1;i<=n;i++)
for(int j=E.Begin[i];j;j=E.Next[j])
if(scc_num[i]!=scc_num[E.to[j]]){
G.add(scc_num[i],scc_num[E.to[j]]);
deg[scc_num[E.to[j]]]++;
}
for(int i=1;i<=scc_cnt;i++)
if(!deg[i])
G.add(scc_cnt+1,i);
dfs_dp(scc_cnt+1);
printf("%d\n",max(0,dp[scc_cnt+1][m]));
return 0;
}