# Connectively # 無向圖連通性 ## 邊、一些定義 **樹邊(tree edge)**:真正在樹上的邊,由父親連到小孩 **回邊(back edge)**:子孫連回祖先 **前向邊(front edge)**:連到子孫的邊(不是樹)邊 **交錯邊(cross edge)**:連到非直系子孫 **內節點**:非根節點與葉節點(也就是說他至少會連兩個邊!) **橋**:拔掉此邊後連通塊加1 **割點/關節點**:拔點此點後連通塊加1 **邊雙連通分量**:在此連通塊內拔掉任何一條邊仍然是連通塊,即連通塊內無橋 * **注意!** 以點為主體,可能有邊不在任何集合內 ![](https://hackmd.io/_uploads/Hkv0wsWvn.png) **點雙連通分量(BCC)**:在此連通塊內拔掉任何一條點仍然是連通塊,即連通塊內無割點 * **注意!** 以點為主體,可能同一點在不同集合內 ![](https://hackmd.io/_uploads/SkXguoZwh.png) * 性質 1. u到v定存在兩條不重複路徑 2. 對於u, v, w,存在由u到v再到w的簡單路徑(由1可以推得) 3. 對於任兩條邊,在同一簡單環上,則若且唯若他們屬於同點雙連通分量 ## Tarjan(塔樣?) 定義low函數為不經過**父節點**所可以抵達的最淺深度 * u還沒走過: u會是v的小孩 從u點走,回傳low(u)看是否比目前小(可能透過回邊走到祖先) * u走過 (v, u)會是一條回邊,檢查depth(u)是否比low(v)小,是的話更新 * **找橋**:如果depth[v] = low[v],則父邊就會是橋 代表 v 在不依靠父邊的情況下永遠沒辦法走到它的祖先,此時v的父邊就會是橋 ```cpp= void dfs(int v, int p) { visited[v] = 1; if (v != p) // not root low[v] = depth[p]+1; for (int u: adj[v]) { if (u == p) continue; if (visited[u]) { if (depth[u] < low[v]) low[v] = depth[u]; } else { dfs(u); if (low[u] < low[v]) low[v] = low[u]; } } if (low[v] == depth[v]) { // (p, v) = bridge if v is not a root vertex } } ``` * **找割點/關節點**: 如果v的子孫們沒有除了透過v到達祖先的方法,v為關節點 **v為root時**,若child >= 2 ,root為關節點 question:為何不能改為判斷式為 low[u] >= dis[u] A: 可能繞回來的點恰好是關節點,遇上這情況會誤判 ```cpp= void dfs(int v, int p) { visited[v] = 1; if (v!=p) low[v] = depth[p]+1; int chd_cnt = 0; for (int u:adj[v]) { if (u==p) continue; if (!visited[u]) { chd_cnt++, dfs(u, v); low[v] = min(low[v], low[u]); if (low[u] >= dis[v] && p!=-1) //v is a non-root cut-vertex } else if (dfs[u] < dfs[v]) low[v] = min(low[v], dis[u]); } if (p==-1 && chd_cnt > 1) //the root of the tree is a cut-vertex } ``` * **找邊雙連通分量** 在遞迴的過程 ```cpp= void dfs(int v, int p) { visited[v] = 1; if (v != p) // not root low[v] = depth[p]+1; stack<int> stk; stk.push(v); for (int u: adj[v]) { if (v==p) continue; if (!visited[u]) { dfs(v, u); low[v] = min(low[v], low[u]); if (low[v] > dis[u]) { bcc_cnt++; while(stk.top()!=p) bcc[bcc_cnt].push_back(stk.top()) } } } } ``` * **找點雙連通分量** ## 例題 ### Cycling city 給一張無向圖,是否有(a, b)可以有三種之間可以有三組路徑(點不重複、邊不重複) # 有向圖連通性 ## 強連通分量 在此連通塊中每一個點都可以到別的點,可以**縮點**之後變成**DAG(有向無環圖)!** ## Kosaraju ## 2-SAT問題 Q:為甚麼不是無向圖? 如果(a或b)的話,若a是True,但b可能是true或false,所以是有向!(若你知道一個是false,另一個一定是True!) 建立¬a -> b, ¬b -> a的邊 接著用Kosaraju做!