hihoCoder #1183 : 连通性一·割边与割点(模板)

#1183 : 连通性一·割边与割点

(模板:求割边和割点)

题目链接

题意:给出一个连通图,求出所有的割点和割边,没有割点的话直接输出Null。

思路:

在dfs树中:
割点:1.该点为dfs树的根结点,若这个根节点有两颗及以上的子树,则为割点
      2.该点不是dfs树的根结点,若v为u的子节点,low[v]>=dfn[u]的话,表示u的子节点v最多能回到祖先节点u,不能回到u的祖先节点了,此时这也是一个节点。

割边:对于一条边<u,v>,若v为u的子节点,low[v]>dfn[u]的话,表示u的子节点v无法回到u结点,此时是<u,v>是一条割边。

以下定义转载于hihoCoder



割边:在连通图中,删除了连通图的某条边后,图不再连通。这样的边被称为割边,也叫做桥。

割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通。这样的点被称为割点。

DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树。

树边:在搜索树中的蓝色线所示,可理解为在DFS过程中访问未访问节点时所经过的边,也称为父子边

回边:在搜索树中的橙色线所示,可理解为在DFS过程中遇到已访问节点时所经过的边,也称为返祖边、后向边

#include<bits/stdc++.h>
using namespace std;
const int maxn = 200000 + 10;
struct Edge {
	int u,v;
};
bool cmd(Edge &a,Edge &b) {
	if(a.u==b.u)
		return a.v<b.v;
	else
		return a.u<b.u;
}
struct tarjan {     //tarjan模板
	int n;
	vector<int>e[maxn];    //边集
	int dfn[maxn];    //dfn数组是个时间戳,就是访问那个节点的时间,也就是第几次调用dfs这个函数
	int low[maxn];    //Low是u的子节点能通过反向边到达的节点DFN的最小值, 初始值为dfn[u]
	int index;        //记录dfs调用的次数
	Edge edge[maxn];  //记录割边
	int node[maxn];   //记录割点
	int f[maxn];      //父亲节点
	int s[maxn];      //儿子节点的个数
	int cnt_edge;     //割边的边数
	int cnt_node;     //割点的点数
	void init(int N) {       //初始化
		n = N;
		for (int i = 1; i <= n; i++)
			e[i].clear();
		index = 0;
		cnt_node=0;
		cnt_edge=0;
		memset(dfn, -1, sizeof(dfn));
		memset(f,0,sizeof(f));
		memset(s,0,sizeof(s));
	}
	void addedge(int u, int v) {   //添加边
		e[u].push_back(v);
	}
	void dfs(int u) {       //dfs类似环缩点的写法,两个主要数组dfn[]和low[]
		dfn[u] = low[u] = ++index;
		bool flag=0;
		for (int i = 0; i<e[u].size(); i++) {
			int &v = e[u][i];
			if (dfn[v] == -1) {
				s[u]++;
				f[v]=u;
				dfs(v);
				if(low[v]>=dfn[u]) {
					flag=1;
				}
				if(low[v]>dfn[u]) {       //low[v]大于dfn[u]表示除原路径外,没有其他路径使得v回到u,即无法形成环,所以是割边
					edge[cnt_edge].u=min(u,v);
					edge[cnt_edge++].v=max(u,v);
				}
				low[u] = min(low[u], low[v]);
			} else if (v!=f[u])
				low[u] = min(low[u], dfn[v]);
		}
		if((f[u]==0&&s[u]>=2)||(f[u]&&flag)) // 1.该点为dfs树的根结点,若这个根节点有两颗及以上的子树,则为割点
			node[cnt_node++]=u;              //2.该点不是dfs树的根结点,若存在v为u的子节点且low[v]>=dfn[u]的话,则也是一个割点
	}
	void solve() {   //遍历所有点
		for (int i = 1; i <= n; i++) {
			if (dfn[i] == -1)
				dfs(i);
		}
	}

} T;
int main() {
	int n,m;
	int u,v;
	scanf("%d %d",&n,&m);
	T.init(n);
	for(int i=1; i<=m; i++) {
		scanf("%d %d",&u,&v);
		T.addedge(u,v);
		T.addedge(v,u);
	}
	T.solve();
	sort(T.edge,T.edge+T.cnt_edge,cmd);
	sort(T.node,T.node+T.cnt_node);
	if(T.cnt_node==0) {
		printf("Null\n");
		return 0;
	}
	for(int i=0; i<T.cnt_node; i++) {
		printf("%d%c",T.node[i],i==T.cnt_node-1?'\n':' ');
	}
	for(int i=0; i<T.cnt_edge; i++) {
		printf("%d %d\n",min(T.edge[i].u,T.edge[i].v),max(T.edge[i].u,T.edge[i].v));
	}
	return 0;
}


不得不说原本的hiho上的解释写的很好 大笑,推荐大家去看看 官方题解(应该吧)


猜你喜欢

转载自blog.csdn.net/qq_40160605/article/details/80037710
今日推荐