使用Tarjan方法计算割点与桥,这里先介绍下概念。
无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。
无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。
一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得dfn(u)<=low(v)。
一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足dfn(u)<low(v)(前提是其没有重边所以先用邻接矩阵存储)。
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]);
if(low[u]>low[u]) u,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;
}
}