給定無向圖 (可能不連通,含孤立點),求最少添加多少條邊使圖變為 雙邊連通 (即無橋,任意兩點間至少有兩條不相交路徑)。
Low[v] > DFN[u])。Low 值 (或用 DFS 染色)。u (孤立點),度為 1 的分量數 v (葉子)。(2*u + v + 1) / 2 (向上取整)。孤立點在 Tarjan 中 head[u]==-1,不會被訪問到。需單獨標記其所在分量 used[Low[u]]=1,並計入度為 0 的計數。公式自然涵蓋:孤立點需加 2 條邊 (自成環或連兩條到別處),度 1 葉子需加 1 條,配對後向上取整。
void Tarjan(int u, int pre) {
Low[u] = DFN[u] = ++Index;
for (int i=head[u]; ~i; i=edge[i].next) {
int v = edge[i].to;
if (v == pre) continue;
if (!DFN[v]) {
Tarjan(v, u);
Low[u] = min(Low[u], Low[v]);
if (Low[v] > DFN[u]) bridge++;
} else Low[u] = min(Low[u], DFN[v]);
}
}
void solve(int N) {
// 1. 找橋
for (int i=1;i<=N;i++) if (!DFN[i]) { Tarjan(i,i); bridge++; }
if (bridge == 1) { puts("0"); return; } // 單點或已雙連通
// 2. 縮點統計度
memset(used,0,sizeof used); memset(dg,0,sizeof dg);
for (int u=1; u<=N; u++) {
if (head[u]==-1) { used[Low[u]]=1; continue; } // 孤立點
for (int i=head[u]; ~i; i=edge[i].next) {
int v = edge[i].to;
used[Low[u]] = used[Low[v]] = 1;
if (Low[u] != Low[v]) dg[Low[u]]++;
}
}
int ans = 0;
for (int i=1;i<=N;i++) {
if (used[i] && dg[i]==0) ans += 2;
else if (dg[i]==1) ans++;
}
printf("%d\n", (ans+1)/2);
}
O(V+E),V ≤ 1000,E ≤ 10^5,極快。