电力

电力

题意

求一个图删除一个点之后,联通块最多有多少。

思路

先计算出原来有多少个联通块,再计算每个点对联通块的贡献的最大值。

考虑跑一遍 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;
}
posted @ 2024-09-01 10:51  maniubi  阅读(6)  评论(0编辑  收藏  举报