Loading

Tarjan

定义

  • 强连通分量:

对于一个有向图,如果图中任意两个结点均连通,那么我们称这个图是强连通的。

对于一个有向图中的极大强连通子图,我们称这个子图为强连通分量。

  • 割点:

对于一个无向连通图中的点,假如删去这个点以及与其相连的所有边之后图不连通,那么称该点为该图的割点。

  • 割边:

对于一个无向连通图中的边,假如删去这条边之后图不连通,那么称该边为该图的割边。

  • 点双连通分量:

对于一个无向图,如果该图不包含割点,那么称我们这个图是点双连通的。

对于一个无向图中的极大点双连通子图,我们称这个子图为点双连通分量。

  • 边双连通分量:

对于一个无向图,如果该图不包含割边,那么我们称这个图是边双联通的。

对于一个无向图中的极大边双连通子图,我们称这个子图为边双连通分量。

强连通分量

void tarjan(int s){
	dfn[s] = low[s] = ++ cnt;
	in[s] = 1; sk[++ tt] = s;
	for (auto v : to[s]) {
		if (!dfn[v]) {
			tarjan(v);
			low[s] = min(low[s], low[v]);
		}
		else if(in[v]) low[s] = min(low[s], dfn[v]);
	}
	if (dfn[s] == low[s]) {
		num ++;
		for (; ; ) {
			int t = sk[tt --];
			rid[t] = num; in[t] = 0;
            scc[num].push_back(t);
			if (t == s) break;
		}
	}
}

点双连通分量

void tarjan(int s, int fr){
    dfn[s] = low[s] = ++ cnt;
    sk[++ tt] = s;
    bool child = 0;
    for (auto v : to[s]) {
        if (!dfn[v]) {
            child = 1;
            tarjan(v, s);
            low[s] = min(low[s], low[v]);
            if (low[v] >= dfn[s]) {
                num ++;
                while (sk[tt + 1] != v) 
                    vDcc[num].push_back(sk[tt --]);
                vDcc[num].push_back(s);
            }
        }
        else low[s] = min(low[s], dfn[v]);
    }
    if (!fr && !child) vDcc[++ num].push_back(s);
}

边双连通分量

void tarjan(int s, int fr) {
    low[s] = dfn[s] = ++ cnt;
	sk[++ tt] = s; in[s] = 1;
	for (int i = head[s]; i; i = nxt[i]) {
		int v = to[i];
		if (!dfn[v]) {
			tarjan(v, i);
			low[s] = min(low[s], low[v]);
			if (low[v] > dfn[s]) bridge[i] = bridge[i ^ 1] = 1;
		}
		else if (i != (fr ^ 1)) low[s] = min(low[s], dfn[v]);
	}
}

void dfs(int s){
	Dcc[num].push_back(s); vis[s] = 1;
	for (int i = head[s]; i; i = nxt[i]) {
		int v = to[i];
		if (vis[v] || bridge[i]) continue;
		dfs(v);
	}
} 
posted @ 2023-06-04 22:26  TKXZ133  阅读(20)  评论(0)    收藏  举报