洛谷 P3387 【模板】缩点 邻接表+Tarjan+栈+染色+缩点+拓扑排序+动归
Tarjan算法,详见https://blog.csdn.net/mrcrack/article/details/103806804
在线测评地址https://www.luogu.com.cn/problem/P3387
样例通过,提交AC.2019-1-3
#include <stdio.h>
#include <string.h>
#define maxn 10010
#define maxm 100010
int n,m;
int head1[maxn],tot1,dfn[maxn],low[maxn],st[maxn],top,color[maxn],w1[maxn],tag,vis[maxn],sum,w2[maxn];
int head2[maxn],tot2,in_degree[maxn],dp[maxn],q[maxn];
struct node{
int to,next;
}e1[maxm],e2[maxm];
void add_edge(int u,int v){
tot1++,e1[tot1].to=v,e1[tot1].next=head1[u],head1[u]=tot1;
}
void add_edge2(int u,int v){
tot2++,e2[tot2].to=v,e2[tot2].next=head2[u],head2[u]=tot2;
}
int min(int a,int b){
return a<b?a:b;
}
void Tarjan(int u){
int b,v;
low[u]=dfn[u]=++tag;
vis[u]=1,st[++top]=u;
for(b=head1[u];b;b=e1[b].next){
v=e1[b].to;
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v])low[u]=min(low[u],low[v]);
}
if(dfn[u]==low[u]){
sum++;
while(1){
v=st[top--];
vis[v]=0,color[v]=sum,w2[sum]+=w1[v];
if(v==u)break;
}
}
}
void build(){//由缩点建图
int b,u,v;
for(u=1;u<=n;u++)
for(b=head1[u];b;b=e1[b].next){
v=e1[b].to;
if(color[u]==color[v])continue;
else add_edge2(color[u],color[v]),in_degree[color[v]]++;
}
}
void top_sort(){
int h,t,b,v,i,u;
h=t=1,memset(vis,0,sizeof(vis));
for(i=1;i<=sum;i++)
if(!in_degree[i])q[t]=i,t++,vis[i]=1,dp[i]=w2[i];//要点,别漏了此句dp[i]=w2[i]
while(h<t){
u=q[h];
for(b=head2[u];b;b=e2[b].next){
v=e2[b].to;
if(dp[v]<dp[u]+w2[v])dp[v]=dp[u]+w2[v];//处理手法有些类似 数字三角形
in_degree[v]--;
if(!in_degree[v]&&!vis[v])q[t]=v,t++,vis[v]=1;
}
h++;
}
}
int main(){
int i,u,v,mx=-1;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&w1[i]);
for(i=1;i<=m;i++)scanf("%d%d",&u,&v),add_edge(u,v);
for(i=1;i<=n;i++)
if(!dfn[i])Tarjan(i);
build();
top_sort();
for(i=1;i<=sum;i++)
if(mx<dp[i])mx=dp[i];
printf("%d\n",mx);
return 0;
}