一、定义:
维基百科:
二、代码:
#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
#define NIL -1
class Graph
{
int n;
list<int> *adj;
void bridgeUtil(int u,bool visited[], int disc[],
int low[], int parent[], int &time);
public:
Graph(int _n){ n = _n; adj = new list<int>[_n]; }
~Graph(){ delete [] adj; }
void addEdge(int v, int w){ adj[v].push_back(w); adj[w].push_back(v); }
void bridge(); //提供给外部调用,完成一些初始化作用,再调用bridgeUtil()
};
bridgeUtil
形参说明:
u:
要处理的下一个顶点
visited[]:
标记是否被访问
disc[]
:disc[u
]第一次被访问的时间(顶点在DFS
生成树中的次序)
low[]
:low[u]
存顶点u能够达到的最早的祖先(disc
值最小的祖先),
一开始先初始化u
第一次被访问的时间,除非在邻居中找到了它的祖先(已经被访问过了,双亲这里不算)
parent[]
:parent[u]
记录u
的双亲
time
:时间戳,传的引用
void Graph::bridgeUtil(int u, bool visited[], int disc[],
int low[], int parent[], int &time)
{
disc[u] = low[u] = ++time;
visited[u] = true;
list<int>::iterator it;
for(it = adj[u].begin(); it != adj[u].end(); it++)
{
int v = *it;
if(!visited[v])
{
parent[v] = u;
bridgeUtil(v,visited,disc,low,parent,time);
low[u] = min(low[u], low[v]);
if(low[v] > disc[u]) //是桥
{
cout<<u<<"-->"<<v<<endl;
}
}
else if( v != parent[u])
{
low[u] = min(low[u], disc[v]);
}
}
}
void Graph::bridge()
{
bool *visited = new bool[n];
int *parent = new int[n];
int *disc = new int[n];
int *low = new int[n];
for(int i = 0; i < n; i++)
{
visited[i] = false;
parent[i] = NIL;
}
int time = 0;
for(int i = 0; i < n; i++)
{
if(!visited[i])
{
bridgeUtil(i,visited,parent,disc,low,time);
}
}
}
和找图的关节点思想是一样的,只是判断是不是关节点的时候用parent[v]!=-1 && low[v]>=disc[u]
来判断,这里用low[v] > disc[u]
来判断。
另外跟找有向图的强连通分量的Tarjan算法也是一个思想。
三、测试:
#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
#define NIL -1
class Graph
{
int n;
list<int> *adj;
void bridgeUtil(int u,bool visited[], int disc[],
int low[], int parent[], int &time);
public:
Graph(int _n){ n = _n; adj = new list<int>[_n]; }
~Graph(){ delete [] adj; }
void addEdge(int v, int w){ adj[v].push_back(w); adj[w].push_back(v); }
void bridge();
};
/*
形参说明:
u:要处理的下一个顶点
visited[]:标记是否被访问
disc[]:disc[u]第一次被访问的时间(顶点在DFS生成树中的次序)
low[]:low[u]存顶点u能够达到的最早的祖先(disc值最小的祖先),
一开始先初始化u第一次被访问的时间,除非在邻居中找到了它的祖先(已经被访问过了,双亲这里不算)
parent[]:parent[u]记录u的双亲
time:时间戳,传的引用
*/
void Graph::bridgeUtil(int u, bool visited[], int disc[],
int low[], int parent[], int &time)
{
disc[u] = low[u] = ++time;
visited[u] = true;
list<int>::iterator it;
for(it = adj[u].begin(); it != adj[u].end(); it++)
{
int v = *it;
if(!visited[v])
{
parent[v] = u;
bridgeUtil(v,visited,disc,low,parent,time);
low[u] = min(low[u], low[v]);
if(low[v] > disc[u]) //是桥
{
cout<<u<<"-->"<<v<<endl;
}
}
else if( v != parent[u])
{
low[u] = min(low[u], disc[v]);
}
}
}
void Graph::bridge()
{
bool *visited = new bool[n];
int *parent = new int[n];
int *disc = new int[n];
int *low = new int[n];
for(int i = 0; i < n; i++)
{
visited[i] = false;
parent[i] = NIL;
}
int time = 0;
for(int i = 0; i < n; i++)
{
if(!visited[i])
{
bridgeUtil(i,visited,parent,disc,low,time);
}
}
}
int main()
{
// Create graphs given in above diagrams
cout << "\nBridges in first graph \n";
Graph g1(5);
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
g1.bridge();
cout << "\nBridges in second graph \n";
Graph g2(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
g2.bridge();
cout << "\nBridges in third graph \n";
Graph g3(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
g3.bridge();
return 0;
}