hdu4587TWO NODES(枚举+割点)

传送门

题目大意:给我们一个无向图,让我们删两个点,让剩下的强连通分量个数最多

思路:N只有5000,所以复杂度可以高一点,所以想到枚举删除一个点,然后对剩下的图

用求割点的方式,求出割去该点后能多出来的连通分量个数,即子树个数,要记得对根节点特判

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 25500;
typedef long long ll;
struct edge {
    int f, t, nxt;
}e[maxn << 1];
int hd[maxn], tot;
void add(int f, int t) {
    e[++tot] = { f,t,hd[f] };
    hd[f] = tot;
}
int n, m;
int low[maxn], dfn[maxn], cnt,no;
int num[maxn];//割去该点的能多出来的联通分量个数
void init() {
    memset(hd, 0, sizeof(hd));
    tot = 0;
}
void dfs(int u, int f) {
    low[u] = dfn[u] = ++cnt;
    int son = 0;
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (v == f||v==no) {continue;}
        if (!dfn[v]) {
            son++;//别写上面了,别问...问就是son表示子连通分量(树)个数
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (u!=f&&low[v] >= dfn[u]) {//是割点
                num[u]++;
            }
        }
        else if (dfn[u]>dfn[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (u == f) {//根节点特判
        num[u] = son - 1;
    }
}
int main() {
    //freopen("test.txt", "r", stdin);
    while (~scanf("%d%d", &n, &m)) {
        init();
        while (m--) {
            int a, b; scanf("%d%d", &a, &b);
            add(a, b);
            add(b, a);
        }
        int ans=0;
        for (int i = 0; i < n; i++) {//枚举删除第一个点,然后求割掉每个点能多出来的联通分量
            no = i;
            memset(dfn, 0, sizeof(dfn));
            memset(num, 0, sizeof(num));
            cnt = 0;
            int colnum = 0;//最初的图也可能是不是强联通的
            for (int v = 0; v < n; v++) {
                if (!dfn[v]&&v!=no) {
                    dfs(v, v);
                    colnum++;
                }
            }
            for (int v = 0; v < n; v++) {
                if(v!=no)ans = max(ans, colnum + num[v]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2021-04-02 16:30  cono奇犽哒  阅读(35)  评论(0)    收藏  举报