//无向图的割点和桥:
//cutnode[u]=true表示u是一个割点
//cutedge(u,v)=true表示(u,v)是一条割边
//Color[u]: 黑 访问完毕 灰 正在访问 白 未访问;
Tarjan(u,father){
DFN[u]=LOW[u]=++time;
//LOW[u]: u以及u的子孙所能到达的最小时间戳
Color[u]=灰;
put u into a stack; //入栈
for each e=(u,v)
if (color[v]==白){
Tarjan(v,u);
LOW[u]=min(LOW[u],LOW[v]);
//若存在边(u,v),且DFN[u]<LOW[v],则(u,v)为一条割边
if (DFN[u]<LOW[v]) cutedge(u,v)=true;
//若存在边(u,v),且DFN[u]<=LOW[v],则u为一个割点;
//当u为根,且至少有2棵子树
//用son[u]记录u的儿子个数,当color[v]=白说明多一个儿子;
son[u]++;
if ((u==root && son[u]>1) || (u!=root && DFN[u]<=LOW[v]))
cutnode[u]=true;
} else
if (v!=father)
LOW[u]=min(LOW[u],DFN[v]);
Color[u]=黑;
//图中一些概念:
//点连通度: 最小割点集合中的点数
//边连通度: 最小割边集合中的边数
//双连通分支: 可理解为任意两点之间有两条路径的极大的子图
//如果一个无向连通图的点/边连通度大于1,则称该图是点/边双连通的;
//当访问结束回退时,若LOW[u]=DFN[u],则有一个双连通分支;
if (LOW[u]==DFN[u]) pop until u;
//弹出元素属于同一个双连通分支;
//双连通分支缩点后会变成一棵树
}
//有向图的强连通分量(分支):
//强连通: 有向图中两个点之间至少有1条路径
//强连通分量: 极大强连通子图;
//与无向图的双连通分支求法一致;
//强连通分支会形成DAG(有向无环图)
//考虑以下问题:
//假设有一个无向图
//求解最小加几条边,使得不存在桥
//缩点后形成了一棵树
//这棵树中度数为1的结点个数为x
//答案就是(x+1)/2
//考虑消除所有度为1的结点即可,连边可以增加它们的度数;
//假设有一个有向图
//求解最小加几条边,使得整张图强连通
//首先求强连通分量缩点
//然后在新的缩点的图中
//求出入度为0点的个数为a,出度为0的点的个数为b
//答案就是max{a,b}
//想法也是简单的,尽量产生环;
图论: 割点、桥(割边)、强连通分量 学习笔记
最新推荐文章于 2023-12-09 15:58:31 发布