版权声明:Powered By Fighter https://blog.csdn.net/qq_30115697/article/details/87024743
Loj10103「一本通 3.6 练习 4」电力
题意
求一个图删除一个点之后,联通块最多有多少。
思路
很显然对于在有割点的情况下,要删除割点,而删除割点后增加的连通块个数可以这样计算:
设num[i]表示第i个点被删除后增加的连通块个数。
- 当前点x为搜索树的根,且孩子的数量大于1,那么删除后连通块的增加量为孩子的数量-1(因为本身就是一个大连通块)。
- 当前点x不是树根,并且有一个儿子v满足 ,则num[x]++;
代码
#include <bits/stdc++.h>
#define reset(x) memset(x, 0, sizeof(x))
#define MAXN 10005
#define MAXM ((int)1e6+5)
using namespace std;
int n, m, cnt;
int head[MAXN], Next[MAXM], vet[MAXM], deg[MAXN];
void add(int x, int y){
cnt++;
Next[cnt] = head[x];
head[x] = cnt;
vet[cnt] = y;
}
bool vis[MAXN];
int low[MAXN], dfn[MAXN], num[MAXN], T, root;
stack<int> s;
void tarjan(int x){
low[x] = dfn[x] = ++T;
vis[x] = true;
s.push(x);
int tot = 0;
for (int i = head[x]; i; i = Next[i]) {
int v = vet[i];
if(!dfn[v]){
tot++;
tarjan(v);
low[x] = min(low[x], low[v]);
if(x==root && tot>1){
num[x] = tot-1;
}
else if(x!=root && dfn[x] <= low[v]){
num[x]++;
}
}
else if(vis[v]){
low[x] = min(low[x], dfn[v]);
}
}
}
void solve(){
int x, y;
for (int i = 0; i < m; ++i) {
scanf("%d %d", &x, &y);
x++, y++;
add(x, y);
add(y, x);
deg[x]++;
deg[y]++;
}
int sum = 0;
for (int i = 1; i <= n; ++i) {
if(!dfn[i]){
sum++;
root = i;
tarjan(i);
}
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
if(!deg[i]){
ans = max(ans, sum-1);
}
else{
ans = max(ans, num[i]+sum);
}
}
cout << ans << endl;
}
void clear(){
cnt = T = 0;
reset(head);
reset(Next);
reset(low);
reset(dfn);
reset(vis);
reset(num);
reset(deg);
while(!s.empty()){
s.pop();
}
}
int main()
{
while(cin >> n >> m && (n+m)>0){
clear();
solve();
}
return 0;
}