提到Tarjan算法就不得不提一提Tarjan这位老人家
Robert Tarjan,计算机科学家,以LCA、强连通分量等算法闻名。他拥有丰富的商业工作经验,1985年开始任教于普林斯顿大学。Tarjan于1986年获得图灵奖。并于1994年当选为ACM院士。
Tarjan其他奖项包括:
奈望林纳奖信息科学(1983第一个获奖者)
国家科学院的研究倡议奖 (1984)
巴黎Kanellakis奖-理论与实践( ACM1999)
帕斯卡奖章数学与计算机科学( 欧洲科学院2004)
加州理工学院杰出校友奖( 美国加州技术研究所2010)
综上所述————Tarjan太强辣!
不扯**了,接下来让我们进入正题
Tarjan求强联通分量算法顾名思义,可以用来求强联通分量(这不是废话吗),同时它还可以用来缩点。所谓缩点,就是将一个强联通分量糅合成一个点,然后将强联通分量里每个个点的信息都整合到这个点里,形成一个超级点
如图所示,1、2、3、4是一个强连通分量,4和5自己是一个强连通分量,那么我们就可以把这张图变成下边这张图
点1这个集合就包含了原来的1、2、3、4四个点,点2是原来的点5,点3是原来的点6,这样我们就可以简化DAG,从而更方便的进行一些操作
例题
- Luogu P2863 [USACO06JAN]牛的舞会The Cow Prom
板子题,没什么好说的,直接上代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
int k=0; char c=getchar();
for(;c<'0'||c>'9';) c=getchar();
for(;c>='0'&&c<='9';c=getchar())
k=(k<<3)+(k<<1)+c-48;
return k;
}
struct zzz{
int t,nex;
}e[50001*2]; int head[10001],tot;
inline void add(int x,int y){
e[++tot].t=y;
e[tot].nex=head[x];
head[x]=tot;
}
int dfn[10001],deep,low[10001],vis[10001],s[100001],tail;
int col,colnum[10001],belong[10001];
//Tarjan缩点主体
void tarjan(int f){
dfn[f]=low[f]=++deep;
s[++tail]=f; vis[f]=1;
for(int i=head[f];i;i=e[i].nex){
int to=e[i].t;
if(!dfn[to]){
tarjan(to);
low[f]=min(low[f],low[to]);
}
else{
if(vis[to])
low[f]=min(low[f],dfn[to]);
}
}
if(dfn[f]==low[f]){
col++;
int v=0;
do
{
v=s[tail--];
vis[v]=0;
colnum[col]++;
belong[v]=col;
}while(v!=f);
}
}
int ans;
int main(){
int n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
add(x,y);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;i++)
if(colnum[i]>1) ans++;
cout<<ans;
return 0;
}