日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法学习:强连通分量 --tarjan

發布時間:2025/7/14 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法学习:强连通分量 --tarjan 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【定義】

【強連通分量】

?在一個子圖中,任意點能夠直接或者間接到達這個子圖中的任意點,這個子圖被稱為強連通分量

?


【解決問題】

求圖的強連通分量

同時能夠起到

...................縮點

...................求割點

...................求割邊

的效果

?


【算法學習】

首先明確我們的目的,找到強聯通分量

所以其實這是一個找環的過程

?

dfn [] :表示 dfs 序

low [] :表示強聯通分量里面 dfs 序最小的 dfs 序

?

方法如下:

?按深度優先遍歷所有節點

?

遍歷當前節點的所有出邊

?

  1.如果當前邊的中點還沒有被訪問過,訪問

  回溯回來之后比較當前節點的 low 值和終點的 low 值

  將較小的變為當前節點的 low 值

?

  2.如果訪問過,則說明我們繞了一個圈

  則比較當前節點的low值和終點的dfn值,將較小的作為當前結點的low值

?

當這個節點的dfn值和low值相等的時候,說明這個點是這個強聯通分量的終點

在這個棧上面的點和這個點都在同一個強聯通分量里面

?

偽代碼如下:

void tarjan(int u) //當前節點 {dfn[u]=low[u]=++cnt;//先默認該點是一個強聯通分量//節點入棧;vis[u]=true;//當前節點已入棧for(遍歷該節點所有出邊){int v=當前邊的終點;if (!dfn[v])//如果沒有被遍歷過 {tarjan(v);//深度優先遍歷low[u]=min(low[u],low[v]);}else low[u]=min(dfn[v],low[u]);}if (low[u]==dfn[u]){//如果找到了最低的那個節點while(棧頂!=v){染色;出棧;}}染色;出棧; }

?


【模板】

【luogu 2863】

【題目大意】求圖內強聯通分量內點個數大于1的強連通分量個數

【題目思路】裸的tarjan求強連通分量

?

再次強調下

分清邊的數量和點的數量

分清雙向邊和單向邊

?

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<stack> using namespace std; const int MAXN = 50010; struct note {int nt;int to; }edge[MAXN]; int top = 0,st[MAXN]; int cnt[MAXN]; int tag[MAXN]; int n, m; void add(int x, int y) {top++; edge[top] = { st[x],y }, st[x] = top; } stack<int> s; int dfn[MAXN], low[MAXN],id,col; bool vis[MAXN]; void tarjan(int now) {dfn[now] = low[now] = ++id;vis[now] = true;s.push(now);for (int i = st[now]; i != -1; i = edge[i].nt){int to = edge[i].to;if (!dfn[to]){tarjan(to);low[now] = min(low[now], low[to]);}else{if (vis[to]){low[now] = min(low[now], dfn[to]);}}}if (dfn[now] == low[now]){col++; int t;do {t = s.top();s.pop();tag[t] = col;cnt[col]++;vis[t] = false;} while (t != now);}} int main() {scanf("%d%d", &n, &m);memset(st, -1, sizeof(st));for (int i = 1; i <= m; i++){int x, y;scanf("%d%d", &x, &y);add(x, y);}int ans = 0;for (int i = 1; i <= n; i++){if (!tag[i])tarjan(i);}for (int i = 1; i <= col; i++)if (cnt[i] > 1)ans++;printf("%d", ans);return 0; } View Code

?


?

【擴展】

求割點

?

求割邊

?

?


?

轉載于:https://www.cnblogs.com/rentu/p/11331123.html

總結

以上是生活随笔為你收集整理的算法学习:强连通分量 --tarjan的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。