点双联通分量,圆方树和广义圆方树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzj1054689699/article/details/83093461

点双联通分量

边双联通分量想必看这篇博客的同学就会,并且边双联通分量理解和打起来比较简单,就不再赘述了。

点双联通分量,类比边双的定义,它是原图的极大无向子图,满足删去子图中任意一个节点以及与其相邻的边,其余节点仍然连通。

如下图,左中两个均为一个点双联通分量,但最右边图中有两个点双联通分量(上下两部分),因为删去中间的点后他们不能联通
在这里插入图片描述

由最右边的图可以看出,一个点可能属于多个点双联通分量,我们称这些点为割点。
这也带来了麻烦,我们处理边双的时候,直接弹栈即可,但此时我们是否需要多一些讨论?

这就需要引入圆方树

圆方树

圆方树本来是一种用来处理仙人掌问题的数据结构
广义圆方树实际上就是将其拓展到了一般的无向图中,做起来差别不大,我们都可以统称为圆方树。

做题时,常常需要面对有关无向图中两点之间的简单路径(不经过重复点)的问题
无向图中的路径十分麻烦,圆方树可以将我们所需要的信息浓缩到一棵树上。

我们将原本无向图中的点称为圆点。
对于一个点双联通分量,我们建立一个方点来代表它,点双联通分量中的所有点都向这个方点连边。
我们将上面的这些图建成圆方树后,它长这样:
在这里插入图片描述
可以看出,圆方树中只存在圆点与方点之间的边。

构造圆方树,同样可以利用tarjan算法
有些模板是栈里是存储边的(可以看出,一条边只会出现在一个点双中),但存储点操作起来更加的方便

void tarjan(int k,int fa)
{
	st[++st[0]]=k;
	low[k]=dfn[k]=++dfn[0];
	for(int i=fs[k];i;i=nt[i])
	{
		int p=dt[i];
		if(p!=fa)
		{
			if(!dfn[p])
			{
				tarjan(p,k);
				if(low[p]>=dfn[k])//栈中p所在的部分与k构成了一个点双
								  //当low[p]>dfn[k]时,这个点双只有一条边两个点。
				{
					lk(++n1,k),lk(k,n1);//新建方点n1,并向所有点双中的点连边
					while(st[st[0]]!=p) lk(n1,st[st[0]]),lk(st[st[0]],n1),st[st[0]--]=0;
					lk(n1,p),lk(p,n1),st[st[0]--]=0;
				}
				else low[k]=min(low[k],low[p]);
			}
			else low[k]=min(low[k],dfn[p]);
		}
	}
}

利用圆方树,我们避免了大量的讨论。
现在无向图中的路径问题变成了树上路径问题。

某些数据结构大神开发出了(仙人掌分治虚仙人掌仙人掌剖分等毒瘤玩意)。利用圆方树,这些问题都转化成树上的问题,好写又易于理解。

猜你喜欢

转载自blog.csdn.net/hzj1054689699/article/details/83093461