無向圖 N≤5000 點、M 條邊。移除任意 2 個點,求剩餘圖中最大連通分量點數的最大可能值。
del。del 移除後的圖中,跑 Tarjan 割點演算法,得到每個點的割點屬性 iscut[u](改為計數:移除 u 後增加的連通塊數)。del 後的基礎連通塊數 sum(DFS 森林樹根數)。del,最佳第二個點即使 iscut[u] 最大者。總連通塊 = sum + max_cut。del 取最大值。
int pre[MAXN], low[MAXN], iscut[MAXN], dfs_clock;
int del; // 當前移除的點
int dfs(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
for (int i=head[u]; ~i; i=edge[i].next) {
int v = edge[i].to;
if (v == del) continue; // 跳過已移除點
if (!pre[v]) {
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if (lowv >= pre[u]) iscut[u]++; // u 是割點,子樹 v 會分離
} else if (pre[v] < pre[u] && v != fa) {
lowu = min(lowu, pre[v]);
}
}
if (fa < 0) iscut[u]--; // 根節點修正
return lowu;
}
void solve() {
int ans = 0;
for (int del=0; del
del:O(N)O(N+M)O(N(N+M)),N=5000 時約 2.5e7 操作,C++ 1s 內可過。iscut[u]++ 而非布林,直接得到移除 u 後新增的連通塊數。iscut[root]--,因為根無父節點,其子樹數即為割點增加數,但演算法會多算一次。base_cc 需正確計數。head/edge/next 結構。