无向图的连通性与相关问题

无向图的连通性与相关问题

一、相关概念:

给定一张无向图\(G=(V,E)\):

1、割点:若\(x\in V\),从图中删去x以及与x相连的边后,图不连通,则x为割点。

2、割边:若\(e\in E\),从图中删去边e后,图不连通,则e为割边(桥)。

3、点(边)双联通分量:一张图不存在割点(边),则此图为点(边)双连通分量。

4、欧拉路、欧拉回路、欧拉图:若有一条从S到T的路径,满足恰好经过每一条边一次,则该路径为欧 拉路;特别地,当S=T时,此路为欧拉回路;一张所有点度数都为偶数的连通无向图为欧拉图。

二、Tarjan与割边、割点:

Tarjan能够在线性时间内求无向图的割点与割边。

对于Tarjan算法中定义的相关数组与变量不在赘述,直接讲一下判定法则。

割边判定法则:如果对于当前搜索点x,存在一条边\(e=(x,y)\),满足\(low[y]>dfn[x]\),则e为割边。

code:

void Tarjan(int x,int fx) {
	RG int i,y;
	dfn[x]=low[x]=++Time;
	for(i=head[x];i;i=e[i].next)
		if(!dfn[y=e[i].to]) {
			Tarjan(y,x),low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x]) bri[i]=bri[i^1]=1;//成对储存,边从2开始
		}
		else if(y!=fx) low[x]=min(low[x],dfn[y]);
}

割边判定法则:如果对于当前搜索点x,满足\(low[y]≥dfn[x]\),则x是割点。

​ 不过,需要注意的是,当x为Tarjan算法的起点时,x至少需要有两个上述节点才是割点。

void tarjan(int x) {
	RG int i,k,y,num=0;
	dfn[x]=low[x]=++Time;
	for(i=head[x];i;i=e[i].next)
		if(!dfn[y=e[i].to]) {
			tarjan(y),low[x]=min(low[x],low[y]);
			if(dfn[x]<=low[y]) 
				if(x!=RT||++num>1) cut[x]=1;
		}
		else low[x]=min(low[x],dfn[y]);
}

三、Tarjan与双连通分量

记点双连通分量为\(v-DCC\),边双连通分量为\(e-DCC\)

\(e-DCC\) 求法:去掉图中的所有的割边,剩下的每一个连通块都是一个$e-DCC $(直接dfs即可)。

\(e-DCC\) 缩点:直接把每一个连通块对应一个节点即可,可以得到一棵树(或森林)。

void dfs(int x) {// 划分连通块
	RG int i,y;
	vis[x]=1,bel[x]=cnt;// 标记该点为所在e-DCC编号
	for(i=head[x];i;i=e[i].next)
		if(!vis[y=e[i].to]&&!bri[i]) dfs(y);
}

\(v-DCC\) 求法:不是直接去掉所有的割点,剩下的每一个连通块都是一个\(v-DCC\)

​ 因为一条割边只能在一个\(e-DCC\)中,但是一个割点去能在多个\(v-DCC\)中。

​ 所以可以用栈维护一下经过的节点,当存在\(low[y]≥dfn[x]\)成立时,无论x是否为根,都弹栈到y为止

​ 所有这些弹出来的点与点x构成一个\(v-DCC\)

\(v-DCC\) 缩点:每一个的\(v-DCC\)看成一个节点,同时每一个割点也单独看成一个节点。

​ 每一个\(v-DCC\)向它包含的每一个割点连边,得到一颗树。事实上这棵树很棒!(下方的链接随笔e.e.)

​ 割点的记录在新建的点上,其他点记录在对应的\(v-DCC\)上。

for(i=1;i<=n;++i)
	if(cut[i]) bel[i]=++cnt,mtx[cnt]=1;
for(i=1,New();i<=cnt;++i)
	for(j=0;j<vec[i].size();++j) // vec 存的是v-DCC的节点(含割点)
		if(cut[x=vec[i][j]]) make(i,bel[x]);
		else bel[x]=i;

利用缩点,我们就可以进一步解决有关无向图必经边、必经点的问题!←想了解?←。

四、欧拉路问题

无解判定:当且仅当每个点的度都为偶数才存在欧拉回路。

此处仅贴一下\(dfs\)求欧拉回路的模板(递归版):

void dfs(int x) {
	RG int i,y;
	for(i=head[x];i;i=e[i].next) {
		y=e[i].id;
		if(!vis[y]) vis[y]=1,dfs(e[i].to),sta[++top]=y;
        // 将栈中的节点倒序输出就是一条具体的欧拉回路方案
	}
}
posted @ 2019-07-29 17:26  薄荷凉了夏  阅读(1074)  评论(0编辑  收藏  举报