图论---桥(割边)

一、定义:

维基百科:
在这里插入图片描述
在这里插入图片描述

二、代码:

#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; 
}

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值