tarjan--割点,缩点
统一一下代码风格
割点
概念:
在无向连通图中,如果将其中一个点以及所有连接该点的边去掉,图就不再连通,那么这个点就叫做割点(cut vertex / articulation point)。
求法:
tarjan:判断顶点U是否为割点,用U顶点的dnf值和它的所有的孩子顶点的low值进行比较,如果存在至少一个孩子顶点V满足low[v] >= dnf[u],就说明顶点V访问顶点U的祖先顶点,必须通过顶点U,而不存在顶点V到顶点U祖先顶点的其它路径,所以顶点U就是一个割点。对于没有孩子顶点的顶点,显然不会是割点。
code
void tarjan(int x,int fa){
dfn[x]=low[x]=++cnt;
for (int i = head[x];i;i=ed[i].next){
int to=ed[i].to;
if (!dfn[to]){
tarjan(to,fa);
low[x]=min(low[x],low[to]);
if (low[to]>=dfn[x]&&x!=fa) flag[x]=1;
if (x==fa) child++;
}
low[x]=min(low[x],dfn[to]);
}
if (x==fa&&child>=2) flag[fa]=1;
}
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i,i);
for (int i=1;i<=n;i++) if (flag[i]) ans++;
printf("%d\n",ans);
for (int i=1;i<=n;i++) if (flag[i]) printf("%d ",i);
缩点
概念:
有向图的缩点就是把有向图中强连通分量缩成一个点(道理很简单,我到了这个强连通分量的任何一点,那么这个强连通分量就能被我访问了),在处理有向图的连通性问题时有很多作用。
求法:
把在同一个强联通分量的点打上相同的标记,并记录不同标记的强联通分量的大小,按照题意变换就好
code:
void tarjan(int x){
dfn[x]=low[x]=++cnt;
st[++top]=x;
for (int i = head[x];i;i=ed[i].next){
int to=ed[i].to;
if (!dfn[to]){
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if (!col[to]) low[x]=min(low[x],dfn[to]);
}
if (low[x]==dfn[x]){
++color;
int y;
while (y=st[top--]){
strong[color]++;
col[y]=color;
if (x==y) break;
}
}
}
for (int i = 1;i <= n;i++)
if (!dfn[i]) tarjan(i);