1. 程式人生 > >強連通分量模板

強連通分量模板

【題目描述】
   給出一個有向圖有n個點和m條有向邊,輸出連通分量的數量。
 概念:
  1. 什麼是連通分量?
  答:一個有向圖中,選出某些點組成一個團體,這個團體中的任意兩點都可互相到達。那麼:選出來的這些點+這些點之間原有的邊=叫做 連通分量。
  2. 只適合有向圖
  答:如果是無向圖,那麼並查集就可以解決了(還記得“家族”嗎?)
 附加1:什麼是強連通圖?
 答:如果有向圖G的任意兩個頂點都可以互相到達,稱G是一個強連通圖。
 附加2:什麼是強連通分量? 
 答:比如GG是G的最大的強連通子圖,稱為G的強連通分量(可能不止一個,這個不重要)
 


比如輸入樣例1,有3個連通分量:(1)、(2,3,4,5,6)、(7)
比如輸入樣例2,有3個連通分量:(1,2,3)、(4,6,7)、(5)
【輸入格式】
   第一行n和m(1<=n<=20000,1<=m<=20 0000),表示有向圖總共n個點,點的編號由1~n。m表示m條有向邊。
下來m行,每行兩個整數x和y,表示一條有向邊從點x出發到點y。
【輸出格式】
   一行一個整數,表示連通分量的個數。
【樣例1輸入】
7 7
1 2
2 3
3 4
4 5
5 6
6 2
5 2
【樣例1輸出】
3

【樣例2輸入】
7 11
1 2
1 4
2 3
2 5
3 1
3 5
3 6
4 6
5 7
6 7
7 4
【樣例2輸出】
3

#include<cstdio>
using namespace std;
struct edge{int to,next;}a[200001];
int n,m,dfn[20001],low[20001],h[20001],dx,line[20001],top,ans;
bool bo[20001];
void dfs(int x)
{
    dfn[x]=low[x]=++dx;
    line[++top]=x;
    bo[x]=true;
    int y;
    for (int i=h[x];i;i=a[i].next)
    {
        y=a[i].to;
        if (!dfn[y])
        {
            dfs(y);
            if (low[y]<low[x]) low[x]=low[y];
        }
        else if (bo[y]&&dfn[y]<low[x]) low[x]=dfn[y];
    }
    if (dfn[x]==low[x])
    {
        y=0;
        ans++;
        while (x!=y)
        {
            y=line[top--];
            bo[y]=false;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        a[i].to=y;
        a[i].next=h[x];
        h[x]=i;
    }
    for (int i=1;i<=n;i++)
        if (!dfn[i]) dfs(i);
    printf("%d",ans);
    return 0;
}