【2024-ZR-C Day 4】圖論(1)

心灵震荡發表於2024-07-20

1. 強連通分量

1.1. 定義

有向圖中,選取一個點集 \(S\),若對於 \(S\) 中的任意兩點 \(u, v\),都滿足 \(u\) 可以到達 \(v\),則稱 \(S\)強連通的

強連通分量是圖中一個極大的強連通的點集。

性質:把一個有向圖透過強連通分量縮點後,新的圖是一個 DAG.

1.2. Kosaraju 演算法

無向圖中,求解連通分量只需要按照 \(1\)\(n\) 的順序依次考慮每個點。
考慮到 \(i\) 點時,如果 \(i\) 點未被訪問過,就說明找到了一個新的連通分量,從 \(i\) 點開始 DFS 即可找到i所在的連通分量。

有向圖中,上述演算法不成立。

假設 \(A\)\(B\) 是兩個不同的強連通分量,且 \(A\) 可以到達 \(B\),那麼只有先訪問 \(B\),再訪問 \(A\),才能使得上述演算法成立。
也就是說,遍歷順序要保證 \(B\) 中至少有一個點排在所有 \(A\) 中的點之前。
考慮縮點後得到的 DAG,每次應訪問出度為 \(0\) 的點,即按照拓撲序的逆序訪問縮點後的所有節點。

Kosaraju 演算法的思想:

  1. 把圖中所有邊反向,再按照 \(1\)\(n\) 的順序去DFS,到達每個點時將其入棧,得到每個點的出棧序列 \(q_1, q_2, \ldots, q_n\),即為縮點後的拓撲序.
  2. 按照 \(q_n,\ldots, q_1\) 的順序去 DFS 原圖就是一個合法的順序。

因為把邊反向與否不改變強連通分量,所以得到一個簡化的演算法:

  1. 按照 \(1\)\(n\) 的順序去 DFS 原圖,得到每個點的出棧序列 \(q\).
  2. 按照 \(q_n\ldots q_1\) 的順序去 DFS 反圖,依次得到每個強連通分量。
#include <bits/stdc++.h>
using namespace std;

bool vis[N];
vector<int> g[2][N];
stack<int> stk;

void dfs1(int u)
{
	vis[u] = 1;
	for(auto v : g[0][u])
		if(!vis[v]) dfs1(v);
	q.push(x);
}

void dfs2(int u, int id)
{
	vis[u] = 0, bel[u] = id;
	for(auto v : g[1][u])
		if(vis[v]) dfs2(v, root);
}

int main()
{
	ios :: sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	for(int i = 1; i <= n; i++)
		if(!vis[i]) dfs1(i);
	while(!stk.empty())
	{
		int u = stk.top(); stk.pop();
		if(vis[u]) dfs2(u, ++idx);
	}
	return 0;
}

2. DFS 樹

一張圖的 DFS 樹是在對其進行 DFS 時,所經過的所有有效邊形成的樹結構。

在構造題中,通常我們用到的是無向圖的 DFS 樹。

無向圖的 DFS 樹滿足所有非樹邊都是返祖邊


3. 邊雙連通分量

3.1. 定義&性質

一個無向連通圖邊雙連通,當且僅當對於任意兩個點,存在兩條不相交的路徑。

邊雙連通分量是圖中一個極大的邊雙連通的點集。

定義割邊為:在無向圖中,該邊所在連通塊不再連通的邊。
邊雙連通的定義中,“存在兩條不相交的路徑”顯然等價於“如果無論刪去哪條邊都不能使它們不連通”,故一個無向連通圖邊雙連通的充要條件是沒有割邊

一個無向圖邊雙縮點後是一棵樹,所有樹邊是割邊。
(若縮點後不是一顆樹,說明還存在環,則環上所有的點在一個邊雙內,這與邊雙連通分量“極大”的定義矛盾。)

3.2. 演算法解析

由【3.1. 定義&性質】,求出所有邊雙連通分量只需求出所有割邊,由割邊斷開後得到的一個連通塊就是一個邊雙連通分量。

取原圖的 DFS 樹,只有樹邊有可能是割邊。

一條非樹邊(由【2. DFS 樹】的性質知,只可能是返祖邊)會覆蓋掉一條鏈上的樹邊,這些樹邊就會被 ban 掉,使用樹上差分(或樹剖)維護,剩下的邊就是割邊。


4. Boruvka 演算法

一個神秘的 MST 求法。

維護一些連通塊(初始都是單點),並進行若干輪連邊。

每一輪中,找到每個連通塊連向其它連通塊的最小邊(需要做不等離散化,以邊權為第一關鍵字,以邊的編號為第二關鍵字)並連上,這一條邊一定會在 MST 中。
(可以根據 Kruscal 的流程證明。)

每輪連通塊數量至少減半,最多進行 \(O(\log n)\) 輪連邊。
最劣時間複雜度 \(O((n + m) \log n)\).

Boruvka 演算法適合用來求完全圖(或非常稠密圖)的 MST.


5. 例題

5.1. CF555E Case of Computer Network

給定一張 \(n\) 個點 \(m\) 條邊的無向圖和 \(q\) 組有向點對 \((s, t)\)
詢問是否存在使得所有 \(s\) 都能到達 \(t\) 的無向圖中每條邊的定向方案。
\(n,m,q \le 2 \times 10^5\).

有一個顯然的結論:

在邊雙連通分量中可定向,使得內部構成強連通。

只需取邊雙中的 DFS 樹,使樹邊向下,非樹邊向上即可。

則在本題中,若 \(s, t\) 在同一邊雙,則不必考慮(一定可以)。
那麼只需考慮 \(s, t\) 在不同邊雙的情況。

考慮將原圖按邊雙縮點成一顆樹。
對於每個詢問 \(s, t\),在樹上的路徑一定為 \(s\) 到根之間向上、根到 \(t\) 之間向下。

可以使用樹鏈剖分+線段樹區間覆蓋來做,做的過程中 check 當前要定向的邊中是否有邊已經被定了相反的方向。

5.2. CF1364D Ehab's Last Corollary

給定一個無向連通圖和正整數 \(k\),求一個大小為 \(\lceil \frac{k}{2} \rceil\) 的獨立集或大小不超過 \(k\) 的環(求出任意一個即可)。

首先找到圖中的最小環。

  • 若環的大小不超過 \(k\),則已經得到了解。
  • 若環的大小大於 \(k\):對環進行黑白染色,由狄利克雷抽屜原理,必然存在一個顏色全部相同的大小大於 \(\lceil \frac{k}{2} \rceil\) 的獨立集,從其中任選 \(k\) 個點即可。

問題轉化為如何求最小環。

對於一條非樹邊 \((u, v)\),定義 \(w_{u, v} = |dep_v - dep_u|\).
找到圖中 \(w\) 最小的非樹邊,它和 \(u, v\) 之間的所有樹邊構成最小環。

5.3. CF1103C Johnny Solving

給定一張 \(n\) 個點 \(m\) 條邊的無向連通圖,以及一個整數 \(k\),保證每個點度數 \(\ge 3\),你需要找到一個至少有 \(\lceil \frac{n}{k} \rceil\) 個點的路徑,或者找出 \(k\) 個環,其中每個環的環長都不是 \(3\) 的倍數,且每個環中至少有一個點在這 \(k\) 個環裡只出現一次。

任取一棵 DFS 樹。

  • 如果最大深度 \(\lceil \frac{n}{k} \rceil\),則找到了路徑。
  • 否則,根據樹的性質,至少有 \(k\) 個葉子。
    由題中“保證每個點度數 \(\ge 3\)”的限制知,對於每個葉子,其至少有兩條返祖邊。
    任取其中兩條,根據模 \(3\) 的餘數分討後不難發現,一定存在一個包含這個葉子的環,滿足其環長不是 \(3\) 的倍數。

5.4. LG5811 [IOI2019] 景點劃分

給定一個 \(n\) 個點、\(m\) 條邊的無向連通圖,以及三個整數 \(a, b, c\),滿足 \(a + b + c = n\),你需要將 \(n\) 個點分成三個集合 \(A, B, C\),大小分別為 \(a, b, c\),使得其中至少兩個集合是連通的 (集合中的任意兩個點能只經過該集合內的點互相到達),或者報告無解。

不妨設 \(a \le b \le c\),則讓集合 \(A, B\) 連通的限制一定是最松的。

考慮原圖是樹的情況。我們想找到一條邊,讓它兩側的點數分佈儘量均勻。

考慮重心,找到所有以重心為根的子樹中最大的一個,連線這棵子樹與重心的邊即為該邊。有解當且僅當子樹 \(size \ge a\).

相關文章