简单算法-点双连通分量(无向图)

一、什么是点双连通分量?

       在一个图的一个任意分量中,任意两个点的相连都存在至少两条点不重复的路径。是不是很难理解?其实也可以这样理解:把这个分量从该图中分离出来,如果该分量中没有割点,那么该分量就是一个点连通分量。比如:

 如果把1,2,3结点及他们的边分离出来,就成了一个三角,在这个分量中是不存在割点的。

二、算法思维

       现在我们知道点双连通分量个割点有关,所以代码的整体结构也和割点的差不多。我们在求割点时,已经完成了对一次极大点双连通分量的访问。所以我们只需要把我们访问过的边(这里一定是存储边,用栈)存储起来,在后面判断割点时,若是一个点是割点,则输出该割点到下一个割点中间的边,这些边组合起来就是一个点双连通分量。

为什么是存储边呢? 因为一个割点属于至少一个点双连通分量,存点会出现某个点双连通分量缺少点的情况。

三、代码实现

#include <iostream>
#include <vector>                            
#include <stack>
using namespace std;

typedef struct edge {                  //存入栈中的边
	int from, to;
}Edge;

vector<int>G[20];                     //存所有边
stack<Edge>s;
int low[20], num[20];                  //割点数组
int dfn = 0;                          //递归深度

void dfs(int u, int fa) {            //整体代码和割点差不多,加上了入栈和输出
	Edge* tail;
	low[u] = num[u] = ++dfn;
	for (int i = 0; i < G[u].size(); i++) {
		int v = G[u][i];
		tail = new edge;
		if (!num[v]) {
			tail->from = u;  tail->to = v;         //入栈边
			s.push(*tail);
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if (num[u] <= low[v]) {                        //碰到割点直接输出  直到这个割点连接的边出栈
				cout << "分界线" << endl;   //输出
				while (true) {
					int v = s.top().from;
					cout << s.top().from << "---" << s.top().to << endl;
					s.pop();
					if (v == u) break;    //出栈停止条件
				}
				cout << endl;
			}
		}
		else if (num[u] > num[v] && v != fa) {               //若指向已经访问过的点 也应该把改变存储起来  比如成环
			low[u] = min(low[u], num[v]);                    //v != fa 防止了1--2    2--1的出现
			tail->from = u;  tail->to = v;
			s.push(*tail);
		}
	}
}
int main() {
	int N, M, from, to;
	cout << "请输入点数 和 边数:";
	cin >> N >> M;
	memset(low, 0, sizeof(low));
	memset(num, 0, sizeof(num));
	dfn = 0;
	for (int i = 1; i <= M; i++) {
		cin >> from >> to;
		G[from].push_back(to);
		G[to].push_back(from);
	}
	for (int i = 1; i <= N; i++)   //防止它不是连通图
		if (!num[i])
			dfs(i, -1); 
	cout << endl;
	system("pause");
	return 0;
}

                                                                                                           --请多指教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值