電力
題意
求一個圖刪除一個點之後,聯通塊最多有多少。
思路
先計算出原來有多少個聯通塊,再計算每個點對聯通塊的貢獻的最大值。
考慮跑一遍 tarjan,孤立點的貢獻為 \(-1\),非割點貢獻為 \(0\),割點貢獻為 dfs 樹上 \(low_v \ge dfn_u\) 的 \(v\) 的個數,根的貢獻為 dfs 樹上的兒子個數減一。
程式碼
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
int n, m, cnt, ans, d, dfn[N], low[N];
int tot, ver[N << 1], nxt[N << 1], head[N];
void add(int x, int y) {
ver[++ tot] = y;
nxt[tot] = head[x];
head[x] = tot;
}
void tarjan(int x, int fa) {
low[x] = dfn[x] = ++ cnt;
int son = 0, CNT = 0;
for (int i = head[x], y; i; i = nxt[i]) {
y = ver[i];
if (!dfn[y]) {
tarjan(y, x); son ++;
low[x] = min(low[x], low[y]);
CNT += (low[y] >= dfn[x]);
} else if (y != fa)
low[x] = min(low[x], dfn[y]);
}
if (!fa && !son) d = max(d, -1); // 孤立點
if (!fa && son == 1) d = max(d, 0); // 非割點
if (fa) d = max(d, CNT); // 割點
if (!fa && son >= 2) d = max(d, son - 1); // 根
}
int solve() {
cin >> n >> m;
if (!n && !m) return 1;
memset(head, 0, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
tot = 0, cnt = 0, ans = 0, d = -1e9;
for (int i = 1, u, v; i <= m; i ++) {
cin >> u >> v, u ++, v ++;
add(u, v); add(v, u);
}
for (int i = 1; i <= n; i ++)
if (!dfn[i]) {
ans ++;
tarjan(i, 0);
}
if (d == -1e9) d = 0;
cout << ans + d << "\n";
return 0;
}
int main() {
while (1)
if (solve())
break;
return 0;
}