电力
题意
求一个图删除一个点之后,联通块最多有多少。
思路
先计算出原来有多少个联通块,再计算每个点对联通块的贡献的最大值。
考虑跑一遍 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;
}
标签:电力,int,max,son,fa,dfn,low
From: https://www.cnblogs.com/maniubi/p/18391088