tarjan的用处很多
对有向图:求强联通分量
对无向图:求割点、求桥。特别地,可以分离仙人掌图里的环
先贴一个看到不错的博客:点击打开链接
//有向图强联通分量
void tarjan(int x){
dfn[x] = low[x] = ++times;
S.push(x);f[x] = true;
for (int i = head[x];i;i = nex[i])
if (!dfn[des[i]]){
tarjan(des[i]);
low[x] = min(low[x], low[des[i]]);
}
else if (f[des[i]]) low[x] = min(low[x], dfn[des[i]]);
if (dfn[x] == low[x]){//block in stack S
nn++;
int y;
do{
y = S.top();S.pop();
val[nn] ++;f[y] = false;blo[y] = nn;
}while (y != x)
}
}
//无向图求割点或桥,注意割点的判断条件
void tarjan(int x,int pre){
dfn[x] = low[x] = ++times;
int child_cnt = 0;
bool flg = false;
for (int i = head[x];i;i = nex[i]){
int y = des[i];
if (!dfn[y]){
S.push(i);//edges in stack
tarjan(y, i^1);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x]){}//(x, y) is bridge
if (low[y] >= dfn[x]){//point x
flg = true;
}
child_cnt ++;
}
else low[x] = min(low[x], dfn[y]);
}
if (pre == 0 && child_cnt > 1) cnt++;
if (pre && flg) cnt++;
}
//仙人掌图(只有简单环,一条边最多出现在一个环里)求环,例:HDU6041
dfn[x] = low[x] = ++times;
for (int i = head[x];i;i = nex[i]){
int y = des[i];
if (!dfn[y]){
S.push(i);
dfs(y, i^1);
low[x] = min(low[x], low[y]);
if (low[y] >= dfn[x]){
int j;
T.resize(0);
do{
j = S.top();
S.pop();
T.PB(w[j]);
}while (j != i);
}
}
else if (i != pre && dfn[y] < dfn[x])
S.push(i), low[x] = min(low[x], dfn[y]);
}
}
一些细节:1、如果栈内存边,应该top从2开始标号
2、割点的判断条件有两种:如果是根,只需要实边的儿子数大于一,否则需要有满足low[y]>=dfn[x]这个条件的实边儿子。