【Tarjan求强连通分量】【模板】

分析

  1. 首先可以采用dfs的方式,对每个点遍历一遍,若其尚未访问,则以它为起点dfs,那么此次dfs中未遍历到的点一定不可能与遍历到的点形成强连通分量,因为强连通分量要求能够互相到达。
  2. 在一次dfs中,每个scc一定存在一个节点是这个scc中其他所有点的祖先节点。证明:否则,这个scc可以划分为若干棵树,这些树之间只能以横叉边相连,而横叉边只能从dfn序大的指向小的,而强连通分量要求相互到达,且其中任意两棵树一定满足其中的一棵树的所有节点的dfn序一定大于另一颗树的所有节点的dfn序,那么这就会形成矛盾。
  3. 我们考虑维护一个栈,保存所有能够到达当前节点x的节点。那么栈中一定包括所有x的祖先节点,还有通过反向边可以到达x的祖先节点的点。定义low[x]为x能通过最多一条非树边到达的dfn序最小的在栈中的节点。那么当回溯时若有dfn[x]==low[x]则可判定从栈顶到x的所有节点构成一个scc
  4. 访问到一个新节点x时,把x压进栈,dfn[x]=low[x]=++tot.
  5. 对于x连向的每个节点y:若y尚未访问过,则(x,y)是树枝边,先dfs(y),用lowy更新lowx(这里其实有两种情况,见Tip);若y被访问过,且y在栈中,用dfny更新lowx
  6. 回溯时若有若有dfn[x]==low[x],则可一直弹栈直到x出栈,弹出的所有节点构成一个scc
  7. 缩点时枚举每条边,若两端点分属不同scc,则加入新DAG中。
    Tip:若lowy可以到达x,那么满足条件,可以更新lowx。如果lowy不可以到达x,那么lowy一定等于y,大于dfnx,一定不会对lowx造成影响。

Code(校园网络,虽然里面的记录的scc没什么用,但在别的题中也许会用到)

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read()
{
register int x=0,w=1;
register char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') {w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=~(x-1);
if(x>9) write(x/10);
putchar('0'+x%10);
}
const int N=1e4+100;
int n,ins[N],stk[N],top,tot,c[N],dfn[N],low[N],cnt,ind[N],od[N];
vector<int>v[N],scc[N];
void tarjan(int x)
{
dfn[x]=low[x]=++tot;stk[++top]=x;ins[x]=1;
for(int i=0;i<v[x].size();++i)
{
int y=v[x][i];
if(!dfn[y]){
tarjan(y); low[x]=min(low[x],low[y]);
}
else if(ins[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
cnt++;int z;
do
{
z=stk[top--];
scc[cnt].push_back(z);c[z]=cnt;ins[z]=0;
}while(z!=x);
}
}
signed main()
{
n=read();
for(int i=1;i<=n;++i)
{
int x=read();
while(x) v[i].push_back(x),x=read();
}
for(int i=1;i<=n;++i){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;++i)
{
for(int j=0;j<v[i].size();++j)
{
int y=v[i][j];
if(c[i]==c[y]) continue;
od[c[i]]++;ind[c[y]]++;
}
}
int a=0,b=0;
for(int i=1;i<=cnt;++i) {
if(ind[i]==0) a++;
if(od[i]==0) b++;
}
write(a);puts("");
if(cnt==1) {
puts("0");return 0;
}
write(max(a,b));
return 0;
}
posted @   glq_C  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示