HDU 4635 - Strongly connected(强连通)

来源:互联网 发布:ssh怎么指定端口号 编辑:程序博客网 时间:2024/05/16 13:43

`题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4635

`题意:

给你一个图, 若为强连通图,则输出-1.

否则求出至多加上多少边使图为非强连通图.

`思路:

从正面加边无法进行, 则从反面想, 一个非强连通图最多有多少边, 再减去已存在的边.

若强连通分量为1, 则输出-1.

否则, 强连通缩点, 将点分成两部分,X和Y. X和Y之间只能有一个方向指向, 而X或Y内部则可以互相指向.

枚举入度或者出度为0的点,从而得到的最大的答案.

AC.

#include <iostream>#include <cstdio>#include <vector>#include <stack>#include <cstring>#include <cmath>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 1e5+5;int n, m;int in[maxn], out[maxn];vector<int> G[maxn];int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;int cnt[maxn];stack<int> S;void dfs(int u){    pre[u] = lowlink[u] = ++dfs_clock;    S.push(u);    for(int i = 0; i < G[u].size(); ++i) {        int v = G[u][i];        if(!pre[v]) {            dfs(v);            lowlink[u] = min(lowlink[u], lowlink[v]);        }        else if(!sccno[v]) {            lowlink[u] = min(lowlink[u], pre[v]);        }    }    if(lowlink[u] == pre[u]) {        scc_cnt++;        while(1) {            int x =  S.top(); S.pop();            sccno[x] = scc_cnt;            cnt[scc_cnt]++;            if(x == u) break;        }    }}void find_scc(){    dfs_clock = scc_cnt = 0;    memset(sccno, 0, sizeof(sccno));    memset(pre, 0, sizeof(pre));    memset(cnt, 0, sizeof(cnt));    for(int i = 0; i < n; ++i) {        if(!pre[i]) dfs(i);    }}int main(){//freopen("in", "r", stdin);    int T;    scanf("%d", &T);    int ca = 1;    while(T--) {        scanf("%d %d", &n, &m);        for(int i = 0; i < n; ++i)            G[i].clear();        for(int i = 0; i < m; ++i) {            int u, v;            scanf("%d %d", &u, &v);            u--; v--;            G[u].push_back(v);        }        find_scc();        printf("Case %d: ", ca++);        if(scc_cnt == 1) {            printf("-1\n");        }        else if(scc_cnt > 1) {            memset(in, 0, sizeof(in));            memset(out, 0, sizeof(out));            for(int i = 0; i < n; ++i) {                for(int j = 0; j < G[i].size(); ++j) {                    int v = G[i][j];                    if(sccno[v] == sccno[i]) continue;                    in[sccno[v]]++;                    out[sccno[i]]++;                }            }            ll res = 0;            for(int i = 1; i <= scc_cnt; ++i) {                if(in[i] == 0 || out[i] == 0) {                    res = max(res,  (ll)cnt[i]*(n-cnt[i]) + //X与Y之间的边数                                    (ll)(n-cnt[i])*(n-cnt[i]-1) + //Y 内的边数                                    (ll)cnt[i]*(cnt[i]-1)); //X内的边数                    //printf("%lld\n", res);                }            }            //printf("%lld\n", res);            printf("%I64d\n", res - m);        }    }    return 0;}


0 0