淺談雙連通分量、強連通分量


        初談這個話題相信每一位都會感到一絲疑惑,主要原因是這個詞中“分量”一詞,當然,如果僅是為了了解和使用這兩個術語,就不必在意這個無關大體的詞語。

        好了,該談談正題了,所謂雙連通與強連通,最大的差別,也是最本質的差別就是前者適用於無向圖中,而后者適用於有向圖。至於兩者的概念是一樣的,就是圖中有a點、b點,從a點可到達b點,同時從b點可到達a點。(若是有向圖必須延方向到達。)

        其中雙連通分量可細分為:點-雙連通分量,邊-雙連通分量。所謂點-雙連通分量是指在一個無向圖中兩點間至少有兩條路徑,且路徑中(不算頭尾)的點不同。不同的點-雙連通分量最多有一個公共點,這個點必定是“割頂”。提到割頂不得不在這里啰嗦一下,割頂(如下圖)就是當刪去這個點時,連通塊的數量會增加。至於什么叫連通塊,可以理解為一個點的集合,若兩點間可直接或間接的連接則兩點在同一連通塊中。

割頂and橋

至於邊-雙連通分量是指在一個無向圖中兩點間至少有兩條路徑,且路徑中的邊不同。邊-雙連通分量中一定沒有橋。而橋(如上圖)是指當刪去這個邊時,連通塊的數量會增加。

       知識性的東西已經科普完了,下面大致說一下程序。

判斷無向連通圖是否連通:

void dfs(int v)
{
      node_pointer w;
     visited[v] = TRUE;
     for(w = graph[v]; w; w = w->link)
    {
         if(!visited[w->vertex])
        {
              dfs(w->vertex);
        }
    }
}
void connect()
{
     for(int i = 0; i < n; i++)
    {
         if(!visited[i]) 
        {
              dfs(i);
        }
    }
}

求點-雙連通圖:

stack<int> s; 
int num=1,time=0;
int id[1000]={0}; 

void tarjan(int x, int fa)
{
    dfn[x]=low[x]=time++; 
    for(int e=first[x];e!=-1;e=next[e])
    { 
        if(x!=fa&&dfn[x]<dfn[v[e]])
        {
            s.push(e); 
            
            if(dfn[x]==0)
            {
                  tarjan(v[e], x);
                  if(low[v[e]]<low[x])   low[x]=low[v[e]]; 
                  if(low[v[e]]>=dfn[x])
                  { 
                      int edge; 
                      do
                      { 
                          s.pop();
                          edge=s.top();
                          id[u[edge]]=id[v[edge]]=num++;
                      }while(u[edge]!=x||v[edge]!=v[e]);
                  }
            } 
            else if(dfn[v[e]]<low[x]) low[x]=dfn[v[e]]; 
        }
    }
}

求邊-雙連通圖:

void(int u,int fa)
{ 
    dfn[u]=low[u]=++time;
    s[top++]=u; 
    
    for(int e=first[u];e!=-1;e=next[e]) 
    {
        if(v[e]!=fa)
        { 
            if(!dfn[v[e]])
            {
                tarjan(v[e],u); 
                
                if(low[v[e]]<low[u])  low[u]=low[v[e]]; 
                else if(low[v[e]]>dfn[u])
                { 
                    for(s[top]=-1;s[top]!=v[e];)
                    {
                        id[s[--top]]=num;
                        num++;
                    }
                }
            } 
            else if(dfn[v[e]]<low[u])  low[u]=dfn[v[e]];
        }
    }
}

求強連通圖:

void tarjan(int i)
{
    int j;
    DFN[i]=LOW[i]=++Dindex;
    instack[i]=true;
    Stap[++Stop]=i;
    
    for (edge *e=V[i];e;e=e->next)
    {
        j=e->t;
        if (!DFN[j])
        {
            tarjan(j);
            if (LOW[j]<LOW[i])  LOW[i]=LOW[j];
        }
        else if (instack[j] && DFN[j]<LOW[i])  LOW[i]=DFN[j];
    }
    
    if (DFN[i]==LOW[i])
    {
        Bcnt++;
        do
        {
            j=Stap[Stop--];
            instack[j]=false;
            Belong[j]=Bcnt;
        }while (j!=i);
    }
}
void solve()
{
    Stop=Bcnt=Dindex=0;
    
    memset(DFN,0,sizeof(DFN));
    
    for (int i=1;i<=N;i++)
    {
        if (!DFN[i])  tarjan(i);
    }
}

感謝各位觀看我的博客,如有不足歡迎提出,同時希望你們能有所收獲,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM