1. 程式人生 > >Light OJ - 1026 - Critical Links(圖論-Tarjan算法求無向圖的橋數) - 帶詳細註釋

Light OJ - 1026 - Critical Links(圖論-Tarjan算法求無向圖的橋數) - 帶詳細註釋

tdi lan [] spl 頂點 ace 開始 else lose

  原題鏈接

  無向連通圖中,如果刪除某邊後,圖變成不連通,則稱該邊為橋。

  也可以先用Tajan()進行dfs算出所有點 的low和dfn值,並記錄dfs過程中每個 點的父節點;然後再把所有點遍歷一遍, 看其low和dfn,滿足dfn[ fa ]<low[ i ](0<i<=n, i 的 father為fa) —— 則橋為fa-i。 找橋的時候,要註意看有沒有重邊;有重邊,則不是橋。

  另外,本題的題意及測試樣例中沒有重邊,所以不用考慮重邊。

  


帶詳細註釋的題解:

技術分享圖片
#include<stdio.h>
#include<string.h>
#include
<math.h> #include<iostream> #include<algorithm> #include<stack> #include<vector> #define maxn 10010 using namespace std; int dfn[maxn],low_link[maxn] ,Father[maxn]; //tarjan 算法的dfn ——在DFS過程中 的訪問序號(也可以叫做開始時間 //tarjan 算法的low_link[i]——從i節點出發DFS過程中i下方節點所能到達的最早的節點的 開始時間 int bridgenum, Time ,n ; //
橋的總數,dfn時間戳,n為頂點數, vector<int>G[maxn]; //定義圖的鄰接矩陣表 stack<int>st; struct node{ int u,v; }bridge[maxn]; //整個圖的橋的存儲 bool cmp( node a,node b ) { if(a.u!=b.u)return a.u<b.u; else return a.v<b.v; } void init(){ int i; for(i=0;i<=n;i++) //初始化鄰接表 G[i].clear(); bridgenum
=0;Time=0; memset(dfn,0,sizeof(dfn)); memset(low_link,0,sizeof(low_link)); memset(Father,0,sizeof(Father)); } void tarjan(int u,int fa) { low_link[u]=dfn[u]=++Time; Father[u]=fa; //記錄父節點 // st.push(u); for(int i=0;i<(int)G[u].size();i++){ int v=G[u][i]; if(!dfn[v]){ tarjan(v,u); low_link[u]=min(low_link[u],low_link[v]); } else if(v!=fa){ //不能連接到父節點! low_link[u]=min(low_link[u],dfn[v]); } else{ //這種情況就是有重邊的情況!不予處理,直接跳過! } } } void solve() { for(int i=0;i<n;i++){ if(!dfn[i]) tarjan(i,-1); } int ans=0; for(int i=0;i<n;i++){ int v=Father[i]; if(dfn[v]<low_link[i]&&v!=-1){ //若v-i可以構成父節點 bridge[ans].u=v; //橋的兩條邊 bridge[ans].v=i; if(bridge[ans].u>bridge[ans].v) swap(bridge[ans].u,bridge[ans].v); ans++; } } sort(bridge,bridge+ans,cmp); printf("%d critical links\n",ans); for(int i=0;i<ans;i++){ printf("%d - %d\n",bridge[i].u,bridge[i].v); } } int cal_num(char ch[]){ int len=strlen(ch),s=0; for(int i=1;i<=len-2;i++){ s=s*10+ch[i]-0; } return s; } int main() { int T,cas=0; scanf("%d",&T); while(T--) { init(); char ch[10]; int m ,u,v; //邊數 scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%s",&u,ch); m=cal_num(ch); //截取出數字存入m——邊數 for(int j=1;j<=m;j++){ scanf("%d",&v); G[u].push_back(v); //這裏按單向邊任意一邊存儲就可以了,畢竟是無向圖! G[v].push_back(u); } } printf("Case %d:\n",++cas); solve(); } return 0; }
View Code

Light OJ - 1026 - Critical Links(圖論-Tarjan算法求無向圖的橋數) - 帶詳細註釋