Loj10103「一本通 3.6 练习 4」电力

版权声明:Powered By Fighter https://blog.csdn.net/qq_30115697/article/details/87024743

Loj10103「一本通 3.6 练习 4」电力

题目传送门

题意

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

思路

​ 很显然对于在有割点的情况下,要删除割点,而删除割点后增加的连通块个数可以这样计算:

​ 设num[i]表示第i个点被删除后增加的连通块个数。

  1. 当前点x为搜索树的根,且孩子的数量大于1,那么删除后连通块的增加量为孩子的数量-1(因为本身就是一个大连通块)。
  2. 当前点x不是树根,并且有一个儿子v满足 d f n [ x ] l o w [ v ] dfn[x] \leq low[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;
}

猜你喜欢

转载自blog.csdn.net/qq_30115697/article/details/87024743