双连通分量

点双连通

poj1523

题目链接

题意

  • 给出无向图,求割点,并给出每个割点去掉后会形成几个分量

思路

  • tarjan,会形成几个分量注意根节点的不同即可

代码

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cstddef>
const int N = 1005;
std::vector<int> g[N];
int n, son[N], low[N], num[N], id, root;
bool flag[N];
void init() {
	std::memset(son, 0, sizeof(son));
	std::memset(low, 0, sizeof(low));
	std::memset(num, 0, sizeof(num));
	std::memset(flag, false, sizeof(flag));
	id = 0;
	n = 0;
	for(int i = 1; i < N; ++ i) g[i].clear();
}
void dfs(int u, int fu) {
	num[u] = low[u] = ++ id;
	for(unsigned int i = 0; i < g[u].size(); ++ i) {
		int v = g[u][i];
		if(!num[v]) {
			dfs(v, u);
			low[u] = std::min(low[u], low[v]);
			if(low[v] >= num[u] && u != root) {
				++ son[u];
				flag[u] = true;
			}
		} else if(num[v] < num[u] && v != fu) {
			low[u] = std::min(low[u], num[v]);
		}
	}
	if(son[u] >= 2 && u == root) {
		flag[u] = true;
	}
	return;
}
int main() {
	int u, v, idx = 0;
	while(scanf("%d", &u) && u) {
		scanf("%d", &v);
		init();
		n = std::max(u, n);
		n = std::max(v, n);
		g[u].push_back(v);
		g[v].push_back(u);
		while(scanf("%d", &u) && u) {
			scanf("%d", &v);
			n = std::max(u, n);
			n = std::max(v, n);
			g[u].push_back(v);
			g[v].push_back(u);
		}
		root = n;
		dfs(n, n);
		bool exist = false;
		if(idx >= 1) printf("\n");
		printf("Network #%d\n", ++ idx);
		for(int i = 1; i <= n; ++ i) {
			if(flag[i]) {
				exist = true;
				if(i != root) {
					printf("  SPF node %d leaves %d subnets\n", i, son[i] + 1);
				} else if(i == root) {
					printf("  SPF node %d leaves %d subnets\n", i, son[i]);
				}
			}
		}
		if(!exist) printf("  No SPF nodes\n");
	}
	return 0;
}

边双连通

poj3352

题目链接

题意

  • 给出无向图,问最少添加几条边可使图变为双连通图

思路

  • tarjan更新low[]数组之后,再缩点
  • 缩点之后统计叶子节点,需要加的边的条数等于(叶子节点数 + 1)/ 2

代码

#include <iostream>
#include <cstring>
#include <process.h>
#include <string>
#include <algorithm>
#include <vector>
const int N = 1005;
int n, m, id, low[N], degree[N];
std::vector<int> g[N];
void init() {
	for (int i = 0; i <= n; ++ i) g[i].clear();
	id = 0;
	std::memset(low, 0, sizeof(low));
	std::memset(degree, 0, sizeof(degree));
}
void dfs(int u, int fu) {
	low[u] = ++ id;
	for (unsigned int i = 0; i < g[u].size(); ++ i) {
		int v = g[u][i];
		if(v == fu) continue;
		if(!low[v]) dfs(v, u);
		low[u] = std::min(low[u], low[v]);
	}
}
void tarjan() {
	int cnt = 0;
	for (int i = 1; i <= n; ++ i) {
		for(unsigned int j = 0; j < g[i].size(); ++ j) {
			if(low[i] != low[g[i][j]]) ++ degree[low[i]];
		}
	}
	for (int i = 1; i <= n; ++ i) {
		if(degree[i] == 1) ++ cnt;
	}
	printf("%d\n", (cnt + 1) / 2);
}
int main() {
	while (scanf("%d %d", &n, &m) != EOF) {
		init();
		for (int i = 1; i <= m; ++ i) {
			int u, v;
			scanf("%d %d", &u, &v);
			g[u].push_back(v);
			g[v].push_back(u);
		}
		dfs(1, 1);
		tarjan();
	}
	system("pause");
	return 0;
}

原文链接: https://www.cnblogs.com/lemonsbiscuit/p/17087902.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    双连通分量

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/315809

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 下午1:55
下一篇 2023年2月16日 下午1:56

相关推荐