您的位置:首页 > 其它

Tarjan算法求解一个无向图中的割点和桥问题

2016-10-27 13:29 239 查看

基本概念

割点:Articulation Point

在无向连通图中,删除一个顶点v及其相连的边后,原图从一个连通分量变成了两个或多个连通分量,则称顶点v为割点,同时也称关节点(Articulation Point)。

双连通的图:一个没有关节点的连通图称为重连通图(biconnected graph)(双连通图)。

连通度:k,若在连通图上至少删去k 个顶点才能破坏图的连通性。

算法应用

算法应用:通信网络中,用来衡量系统可靠性,连通度越高,可靠性越高。

求解方法

暴力求解,依次删除每一个节点v,用DFS(或者BFS)判断是否连通,再把节点加入图中。若用邻接表(adjacency list),需要做V次DFS,时间复杂度为O(V∗(V+E))O(V∗(V+E))

Jarjan算法,只用一次DFS求解。

第一个方法不多说:

对于第二个方法

我们要维持两个数据结构:

dfn[u]:记录节点u在DFS过程中被遍历到的次序号。

low[u]:记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)。

其中对于low[u]的理解是这样的:当(u,v)为树边时,且v没有被访问过,则low[u]是min(low[u]和low[v])。当v被访问过,如果v不是u的父节点(如果是则说明有重边,不考虑),则(u,v)为回边,则low[u]取min(low[u], dfn[v])。





代码思路解析

#include<iostream>
#include<vector>
#include<fstream>
using namespace std;
#define N 201
vector<int>G
;
bool visit
;
int dfn
;
int low
;
int parent
;
int min(int a, int b)
{
if (a < b) return a;
else return b;
}
void input()
{
int n, m;//分别表示顶点数和边数
ifstream in("input.txt");
in >> n >> m;
int a, b;
for (int i = 1; i <= m; ++i)
{
in >> a >> b;
G[a].push_back(b);/*邻接表储存无向边*/
G[b].push_back(a);
}
}

void dfs(int u)
{
//记录dfs遍历次序
static int counter = 0;
//记录节点u的子树数
int children = 0;
visit[u] = true;
//初始化dfn与low
dfn[u] = low[u] = ++counter;
for (int j = 0; j < G[u].size(); j++)//遍历与u相连的顶点
{
int v = G[u][j];
if (!visit[v])
{
children++;
parent[v] = u;//u是v的父节点
dfs(v);//深度优先搜索v
low[u] = min(low[u], low[v]);//等v完成深度优先搜索之后,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)
if (parent[u] == -1 && children > 1)//对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
{
cout << "1 articulation point: " << u<<endl;
}
if (parent[u] != -1 && low[v] >= dfn[u])//对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边(条件low[v] >= dfn[u]表达的就是),说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。
{
cout << "2 articulation point: " << u << endl; //这样做,可能出现某个顶点多次输出,其实可以用一个指示变量来指示,做到顶点不重复输出
}
if (low[v] >dfn[u]) //桥的条件
{
cout << "Bridge " << v << " " << u << endl;
}

}
else if (v != parent[u]) {//节点v已访问,则(u,v)为回边,且不是重边
low[u] = min(low[u], dfn[v]);
}
}

}

int main()
{
/*input();
memset(dfn, -1, sizeof(dfn));
memset(father, 0, sizeof(father));
memset(low, -1, sizeof(low));
memset(is_cut, false, sizeof(is_cut));
count();*/
memset(dfn, -1, sizeof(dfn));
memset(low, -1, sizeof(low));
memset(visit, false, sizeof(visit));
memset(parent, -1, sizeof(parent));
input();
dfs(1);
system("pause");
return 0;
}




参考

两个很好的讲解很详细的参考资料:

http://www.cnblogs.com/en-heng/p/4002658.html

http://www.cnblogs.com/c1299401227/p/5402747.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: