Tarjan演算法求割點和割邊
阿新 • • 發佈:2018-12-01
目錄
名詞解釋
割點:在無向圖中,刪除某個節點後,圖的連通分量數量增加,則稱該節點為割點
橋:如果刪除某條邊後,連通圖變得不再連通,則此條邊為橋,或者為割邊
Tarjan演算法
在Tarjan演算法中,有兩個十分重要的陣列,dfn陣列,low陣列
dfn陣列:表示dfs遍歷到該節點的序號,也就是順序值
low陣列:表示當前頂點不通過父親節點能訪問到的祖先節點(父親節點上面的節點)中的最小順序值
割點求解:
如果,至少存在一個兒子節點必須要經過父親節點才能訪問到祖先節點,那麼這個父親節點即為割點,假設父親節點為u,兒子節點為v,那麼滿足:low[v] >= dfn[u] 說明:節點u為割點
割邊求解:
相同,割邊的話,兒子節點不經過這條邊就可以訪問到祖先節點,那麼就要滿足:low[v] > dfn[u],如果low[v] == dfn[u],節點v還可以通過其他路徑可以回到u,但是隻包含條件low[x] > dfn[u]時,說明沒有任何一條路可以出了u-v邊外,由u到達v,此時說明,u-v之間的邊為一條割邊
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <vector> using namespace std; typedef long long ll; const int maxn = 10000; int low[maxn],dfn[maxn],head[maxn]; int n,m,tot,k,root; bool flag[maxn]; vector<pair<int,int> > bridge; struct Node { int next,v; }edge[maxn]; void Add_edge(int x,int y) { edge[k].v = y;edge[k].next = head[x];head[x] = k++; edge[k].v = x;edge[k].next = head[y];head[y] = k++; } void Tarjan(int x,int father) { int child = 0; dfn[x] = low[x] = ++tot; for(int i = head[x];i != -1;i = edge[i].next) { int v = edge[i].v; if(!dfn[v]) { child ++; Tarjan(v,x); low[x] = min(low[x],low[v]); if(x != root && dfn[x] <= low[v]) flag[x] = 1; //表示當前節點為割點 if(x == root && child == 2) flag[x] = 1; if(low[v] > dfn[x]) bridge.push_back(make_pair(x,v)); } else if(v != father) low[x] = min(dfn[v],low[x]); } } int main() { memset(head,-1,sizeof(head)); int x,y; scanf("%d%d",&n,&m); for(int i = 0;i < m;i ++) { scanf("%d%d",&x,&y); Add_edge(x,y); } root = 1; //在求解割點、割邊的時候首先確保圖為連通圖 Tarjan(1,root); printf("圖中的割點為:\n"); for(int i = 1;i <= n ;i ++) if(flag[i]) printf("%d ",i); printf("\n"); printf("圖中的割邊為:\n"); for(int i = 0;i < bridge.size();i ++) printf("%d -- %d\n",bridge[i].first,bridge[i].second); printf("\n"); return 0; } /* 6 7 1 4 1 3 4 2 3 2 2 5 2 6 5 6 圖中的割點為: 2 圖中的割邊為: */
參考部落格
https://blog.csdn.net/wtyvhreal/article/details/43530613