无向连通图求割点和桥

无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。
无向连通图中,如果删除某边后,图变成不连通,则称该边为桥

思路和有向图求强连通分量类似,在深度优先遍历整个图过程中形成的一棵搜索树.
dfn[u]定义和前面类似,但是low[u]定义为u或者u的子树中能够通过非父子边(父子边就是搜索树上的边)追溯到的最早的节点的DFS开始时间.

一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得dfn(u)<=low(v)。

一条边(u,v)是桥,当且仅当(u,v)为树枝边,且满足dfn(u)

Tarjan(u)
{
d[u]=low[u]=++index
                for each (u, v) in E
    {
        if (v is not visted)
            tarjan(v)
            low[u] = min(low[u], low[v])
            d[u]<low[v]  (u, v) 是桥
        }
    else
    {
        if(v 不是u 的父节点)
            low[u] = min(low[u], d[v])
        }
}
if (u is root)
u 是割点 <=> u 有至少两个子节点
else
    u 是割点 <=> u 有一个子节点v,满足d[u]<= low[v]
}

也可以先用Tarjan()进行dfs算出所有点的low和dfn值,并记录dfs过程中每个点的父节点,然后再把所有点看一遍,看其low和dfn,以找出割点和桥。找桥的时候,要注意看有没有重边。有重边,则不是桥。

#include <iostream>
#include <vector>
using namespace std;
#define MyMax 200
typedef vector<int> Edge;
vector<Edge> G(MyMax);
bool Visited[MyMax] ;
int dfn[MyMax] ;
int low[MyMax] ;
int Father[MyMax];  //DFS树中每个点的父节点
bool bIsCutVetext[MyMax]; //每个点是不是割点
int nTime; //Dfs时间戳
int n,m; //n是点数,m是边数
void Tarjan(int u, int father) //father 是u的父节点
{
Father[u] = father;
    int i,j,k;
    low[u] = dfn[u] = nTime ++;
    for( i = 0; i < G[u].size() ; i ++ )
    {
        int v = G[u][i];
        if( ! dfn[v])
        {
            Tarjan(v,u);
            low[u] = min(low[u],low[v]);
        }
        else if( father != v )  // 连到父节点的回边不考虑,
            否则求不出桥
            low[u] = min(low[u],dfn[v]);
    }
}
void Count()
{
    //计算割点和桥
    int nRootSons = 0;
    int i;
    Tarjan(1,0);
    for( i = 2; i <= n; i ++ )
    {
        int v = Father[i];
        if( v == 1 )
            nRootSons ++; //DFS树中根节点有几个子树
        else
        {
            if( dfn[v] <= low[i])
                bIsCutVetext[v] = true;
        }
    }
    if( nRootSons > 1)
        bIsCutVetext[1] = true;
    for( i = 1; i <= n; i ++ )
        if( bIsCutVetext[i] )
            cout << i << endl;
    for( i = 1; i <= n; i ++)
    {
        int v = Father[i];
        if(v >0 && dfn[v] < low[i])
            cout << v << "," << i <<endl;
    }
}
int main()
{
    int u,v;
    int i;
    nTime = 1;
    cin >> n >> m ; //n是点数,m是边数
    for( i = 1; i <= m; i ++ )
    {
        cin >> u >> v; //点编号从1开始
        G[v].push_back(u);
        G[u].push_back(v);
    }
    memset( dfn,0,sizeof(dfn));
    memset( Father,0,sizeof(Father));
    memset( bIsCutVetext,0,sizeof(bIsCutVetext));
    Count();
    return 0;
}

你可能感兴趣的:(桥,割点,无向连通图,targan)