Two Spanning Trees(DFS樹,BFS樹)
阿新 • • 發佈:2022-05-17
題意
給定一個\(n\)個點,\(m\)條邊的無向連通圖\(G\),並且\(G\)是簡單圖。找到兩個滿足如下條件的生成樹\(T_1\)和\(T_2\):
-
如果我們把\(T_1\)看作以\(1\)為根節點的有向圖,對於任意一條不包含在\(T_1\)中的邊(非樹邊),兩個點中一個點是另一個點在\(T_1\)中的祖先。
-
如果我們把\(T_2\)看作以\(1\)為根節點的有向圖,對於任意一條不包含在\(T_2\)中的邊(非樹邊),不能出現兩個點中一個是另一個在\(T_2\)中的祖先的情況。
資料範圍
\(2 \leq n \leq 2 \times 10^5\)
\(1 \leq m \leq 2 \times 10^5\)
思路
這道題是DFS樹和BFS樹的模板題。
首先介紹DFS樹。對一個無向連通圖\(G\)進行深度優先遍歷,得到的樹為DFS樹。其中,遍歷到的邊為樹邊,回溯的邊為回邊(非樹邊)。DFS樹的一個重要性質是,圖的回邊連線的都是一個頂點和它在DFS樹中的子孫節點。根據這條性質,我們發現DFS樹滿足\(T_1\)的要求。
然後介紹BFS樹。對一個無向連通圖\(G\)進行寬度優先遍歷,得到的樹為BFS樹。其中,遍歷到的邊為樹邊,回溯的邊為回邊(非樹邊)。BFS樹的一個重要性質是,圖的回邊連線的兩點一定在BFS樹的同一層或者相鄰的兩層。並且,如果處於相鄰兩層,其中一個點不可能是另一個點的父節點(因為如果是父節點,那麼就是樹邊了)。根據這條性質,我們發現BFS樹滿足\(T_2\)
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int N = 200010, M = 2 * N; int n, m; int h[N], e[M], ne[M], idx; bool st[N]; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++; } void dfs(int u) { st[u] = true; for(int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if(!st[j]) { printf("%d %d\n", u, j); st[j] = true; dfs(j); } } } void bfs(int u) { queue<int> que; que.push(u); st[u] = true; while(que.size()) { int t = que.front(); que.pop(); for(int i = h[t]; ~i; i = ne[i]) { int j = e[i]; if(!st[j]) { st[j] = true; que.push(j); printf("%d %d\n", t, j); } } } } int main() { scanf("%d%d", &n, &m); memset(h, -1, sizeof h); for(int i = 0; i < m; i ++) { int a, b; scanf("%d%d", &a, &b); add(a, b), add(b, a); } dfs(1); memset(st, 0, sizeof st); bfs(1); return 0; }