点双边双强连通

点双/边双复习笔记

1.点双复习
割点:图中的一个点,没有这个点的话,这个图会变成两个图
点双:在一个点双内,一个点到另一个点的路径有两条及以上,并且点不会走一样的
注意事项:
1.割点特判:son<=1且fa = x的不是割点
2.环上出发特判:son=0&&fa=x的单独一个作为点双;
3.看好大于等于哦!
4.low[x]=min(low[to],low[x]);和low[x]=min(low[x],dfn[to]);注意区别(默写时这里出了问题)
算法思路:本质上是dfs,在dfs时记录一个点的最先遍历到的时间,成为dfn
维护这个点能到达的(除了不能走父亲连过来的那个边)最小dfn,成为low
利用性质找割点:要是一个节点的儿子dfs完了,但儿子的low是大于这个节点的dfn值,说明他的儿子只能经过父亲节点
回到优先遍历的点去,也就是说是割点,这时候弹栈直到这个儿子被弹出,这些弹出的和这个节点一起作为一个分量
然后这种dfs就叫tarjan(不会便利dfn已经有,也就是已经遍历过的节点)
注意下,老师说else low[x]=min(low[x],dfn[to]);要写else,否则的话可能会错。

重要代码

	void tarjan(int x,int fa){
	++t;
	dfn[x]=t;
	low[x]=t;
	s[++top]=x;
	int son=0;
	for(int i=0;i<mp[x].size();i++){
		int to=mp[x][i];
		if(to==fa){
			continue;
		}
		if(!dfn[to]){
			son++;
			tarjan(to,x);
			low[x]=min(low[to],low[x]);
			if(low[to]>=dfn[x]){
				cut[x]=1;
				cnt++;
				while(s[top+1]!=to){
					bcc[cnt].push_back(s[top]);
					top--;
				}
				bcc[cnt].push_back(x);
			}
		}
		else low[x]=min(low[x],dfn[to]);
		
	}
	if(fa==x&&son==0){
		bcc[++cnt].push_back(x);
	}
	if(fa==x&&son<=1){
		cut[x]=0;
	}
	}

2.点双晚自习背诵默写及练习
https://www.luogu.com.cn/problem/P3225
评测情况:https://www.luogu.com.cn/record/115919126

这个是自己默写了一遍点双,然后wa的,原因是.low[x]=min(low[to],low[x]);	    和          low[x]=min(low[x],dfn[to]);注意区别(默写时这里出了问题)

3.边双复习
割边:一个无向图,割去这条边,图就会分裂成多个图。
边双:不含这个割边的无向图。

写法差不多,和点双的区别在于
	1.判定变为严格>而不是>=
	2.栈的处理需要改变(出栈的结束点不同)
	3.判断条件改变了,而且放在了一个点dfs完后
!!!!!4.!!!!!!!!重边的计算要考虑在内!!!!!!!!!
	(模板没过),不然的话,我可能在fa==to那里错掉,因为
	她不能从父亲dfs过来的那条便那里来,但是可以从另一条边来(重边)
		
	但是,竟然是重边/自环,那么实质上这些重边性质都是相同的,都是链接u和v,然后我们又知道来的那条边有且只有一条
	所以我在代码里加了f,把第一个来自父节点的边不遍历,后面全都继续做
	AC了!!!!!
	https://www.luogu.com.cn/record/115923273

代码:

void tarjan(int x,int fa){
	++t;
	dfn[x]=t;
	low[x]=t;
	top++;
	s[top]=x;
	bool f=0;//用来判重边,自环 
	for(int i=0;i<mp[x].size();i++){
		int to=mp[x][i];
		
		if(to==fa&&f==0){
			f=1;
			continue;
		}
		if(!dfn[to]){
			tarjan(to,x);
			low[x]=min(low[x],low[to]);
		}
		else low[x]=min(low[x],dfn[to]);
	}
	if(low[x]==dfn[x]){
		cnt++;
		while(s[top+1]!=x){
			bcc[cnt].push_back(s[top]);
			top--;	
		}
	}
}

4.强连通分量:
其实强连通分量相比边双而言,就是在else low[x]=min(low[x],dfn[to]);这一句多了一句判断,要求to在栈里面才行
同时记得删去if(to==fa)continue这句,因为强连通分量时有向图

posted @ 2023-07-18 15:27  铃狐sama  阅读(12)  评论(0编辑  收藏  举报