一、连通图
若无向图 G G G 中任意两个不同的顶点 V i V_i Vi 和 V j V_j Vj 都连通(即有路径),则称 G G G 为连通图(Connected Graph)。
二、连通分量
无向图G的极大连通子图称为G的连通分量
三、强连通图
有向图 G G G 中,若对于任意两个不同的顶点 V i V_i Vi 和 V j V_j Vj ,都有 V i V_i Vi 到 V j V_j Vj 及 V j V_j Vj 到 V i V_i Vi 的路径,则称 G G G 为强连通图 (Connected Graph) 。
四、强连通分量
有向图 G G G 的极大强连通子图称为 G G G 的强连通分量,强连通图只有一个强连通分量,即是其自身。非强连通的有向图有多个强连通分量。
求强连通分量
1. kosaraju
void dfs1(int u){
if(vis[u]) return;
vis[u] = 1;
for(int k=head[u];k;k=map[k].next){
int v = map[k].to;
dfs1(v);
}
stk.push(u);
}
void dfs2(int u){
if(SCC[u]) return;
SCC[u] = flag;
for(int k=headT[u];k;k=mapT[k].next){
int v = mapT[k].to;
dfs2(v);
}
}
void kosaraju(){
for(int i=1;i<=n;i++) dfs1(i);
while(!stk.empty()){
int u = stk.top();
stk.pop();
if(SCC[u]) continue;
flag++;
dfs2(u);
}
}
stack <int>stk;
int n,m;
int cnt,cntT,cnt2,flag,ans;
int head[MAXN],headT[MAXN],head2[MAXN];
int pn[MAXN],vis[MAXN],SCC[MAXN],size[MAXN],in[MAXN],f[MAXN];
struct node{
int to,next;
}map[MAXN],mapT[MAXN],map2[MAXN];
void add(node m[],int h[], int u,int v){
m[++cnt] = (node){v,h[u]};
h[u] = cnt;
}
void dfs1(int u){
if(vis[u]) return;
vis[u] = 1;
for(int k=head[u];k;k=map[k].next){
int v = map[k].to;
dfs1(v);
}
stk.push(u);
}
void dfs2(int u){
if(SCC[u]) return;
SCC[u] = flag;
size[flag] += pn[u];
for(int k=headT[u];k;k=mapT[k].next){
int v = mapT[k].to;
dfs2(v);
}
}
void kosaraju(){
for(int i=1;i<=n;i++) dfs1(i);
while(!stk.empty()){
int u = stk.top();
stk.pop();
if(SCC[u]) continue;
flag++;
dfs2(u);
}
}
void topsort(){
queue <int>que;
for(int i=1;i<=flag;i++){
if(!in[i]){
que.push(i);
f[i] = size[i];
}
}
while(!que.empty()){
int u = que.front();
que.pop();
for(int k=head2[u];k;k=map2[k].next){
int v = map2[k].to;
in[v]--;
f[v] = max(f[v],f[u]+size[v]);
if(!in[v]) que.push(v);
}
}
}
int main(void){
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> pn[i];
for(int i=1;i<=m;i++){
int u,v;
cin >> u >> v;
add(map,head,u,v);
add(mapT,headT,v,u);
}
kosaraju();
for(int i=1;i<=n;i++){
for(int k=head[i];k;k=map[k].next){
int v = map[k].to;
if(SCC[i] == SCC[v]) continue;
add(map2,head2,SCC[i],SCC[v]);
in[SCC[v]]++;
}
}
topsort();
for(int i=1;i<=flag;i++)
ans = max(ans,f[i]);
cout << ans;
return 0;
}
2. tarjan
stack <int>stk;
int flag;
int vis[MAXN],dfn[MAXN],low[MAXN];
int SCC[MAXN];
void tarjan(int u){
stk.push(u);
vis[u] = 1;
dfn[u] = low[u] = ++flag;
for(int k=head[u];k;k=map[k].next){
int v = map[k].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v]){
low[u] = min(low[u],dfn[v]);
}
}
int cur;
if(low[u] == dfn[u]){
flag++;
do{
cur = stk.top();
stk.pop();
SCC[cur] = flag;
vis[cur] = 0;
}while(cur != u);
}
}
stack <int>stk;
queue <int>que;
int n,m,cnt,flag,ans,p;
int head[MAXN],pn[MAXN],vis[MAXN],dfn[MAXN],low[MAXN],f[MAXN];
int head2[MAXN],cnt2;
int size[MAXN],in[MAXN],SCC[MAXN];
struct node{
int to,next;
}map[MAXN],map2[MAXN];
void add(int u,int v){
map[++cnt] = (node){v,head[u]};
head[u] = cnt;
}
void add2(int u, int v){
map2[++cnt2] = (node){v,head2[u]};
head2[u] = cnt2;
}
void tarjan(int u){
stk.push(u);
vis[u] = 1;
dfn[u] = low[u] = ++flag;
for(int k=head[u];k;k=map[k].next){
int v = map[k].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v]){
low[u] = min(low[u],dfn[v]);
}
}
int cur;
if(low[u] == dfn[u]){
p++;
do{
cur = stk.top();
stk.pop();
SCC[cur] = p;
size[p] += pn[cur];
vis[cur] = 0;
}while(cur != u);
}
}
void topsort(){
queue <int>que;
for(int i=1;i<=p;i++){
if(!in[i]){
que.push(i);
f[i] = size[i];
}
}
while(!que.empty()){
int u = que.front();
que.pop();
for(int k=head2[u];k;k=map2[k].next){
int v = map2[k].to;
f[v] = max(f[v],f[u]+size[v]);
in[v]--;
if(!in[v]) que.push(v);
}
}
}
int main(void)
{
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> pn[i];
for(int i=1;i<=m;i++){
int u,v;
cin >> u >> v;
add(u,v);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;i++){
for(int k=head[i];k;k=map[k].next){
int v = map[k].to;
if(SCC[i] == SCC[v]) continue;
add2(SCC[i],SCC[v]);
in[SCC[v]]++;
}
}
topsort();
for(int i=1;i<=p;i++){
ans = max(ans,f[i]);
}
cout << ans;
return 0;
}