HDU 4635 Strongly connected(缩点、最多可加边数使得仍然非强连通)

整理的算法模板合集: ACM模板


HDU 4635 Strongly connected

Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the graph is still a simple directed graph. Also, after you add these edges, this graph must NOT be strongly connected.
A simple directed graph is a directed graph having no multiple edges or graph loops.
A strongly connected digraph is a directed graph in which it is possible to reach any node starting from any other node by traversing edges in the direction(s) in which they point.

Input
The first line of date is an integer T, which is the number of the text cases.
Then T cases follow, each case starts of two numbers N and M, 1<=N<=100000, 1<=M<=100000, representing the number of nodes and the number of edges, then M lines follow. Each line contains two integers x and y, means that there is a edge from x to y.

Output
For each case, you should output the maximum number of the edges you can add.
If the original graph is strongly connected, just output -1.

给定一个有向图,求最大可以增加多少条边使得这个图仍然不是强连通图。

HDU 4635 Strongly connected(缩点、最多可加边数使得仍然非强连通)_第1张图片

图片来源

  • 最大可以增加多少条边使得这个图仍然不是强连通图

结论: n ∗ ( n − 1 ) − m − m i n ∗ ( n − m i n v ) n * (n - 1) - m - min * (n - minv) n(n1)mmin(nminv)(其中n为点数、m为边数、minv为缩点以后的点中入度和出度至少有一个为0的包含节点个数最少的点)

#include
#include
#include
#include
#include
using namespace std;

const int N = 500007, M = 5000007, INF = 0x3f3f3f3f;

int n, m;
int head[N], ver[M], nex[M], tot;
int dfn[N], low[N], ind;
int stk[N], top;
int scc_id[N];
int scc_cnt;
bool ins[N];
int scc_num[N];
vector<int>scc[N];
int t;

void add(int x, int y){
     
    ver[tot] = y;
    nex[tot] = head[x];
    head[x] = tot ++ ;
}

void tarjan(int x)
{
     
    dfn[x] = low[x] = ++ ind;
    stk[++ top] = x, ins[x] = true;
    for(int i = head[x]; ~i ; i = nex[i]){
     
        int y = ver[i];
        if(!dfn[y]){
     
            tarjan(y);
            low[x] = min(low[x], low[y]);
        }
        else if(ins[y])
            low[x] = min(low[x], dfn[y]);
    }
    if(dfn[x] == low[x]){
     
        int y;
        scc_cnt ++;
        do{
     
            y = stk[top -- ];
            ins[y] = false;
            scc_id[y] = scc_cnt;
            scc_num[scc_cnt] ++ ;
            scc[scc_cnt].push_back(y);
        }while(x != y);
    }
}

int in[N], out[N];
int ans;
int cnt;
int main()
{
     
    scanf("%d", &t);
    while(t -- ){
     
        cnt ++ ;
        tot = 0, ind = 0, scc_cnt = 0;
        memset(dfn, 0, sizeof dfn);
        memset(low, 0, sizeof low);
        memset(head, -1, sizeof head);
        memset(in, 0, sizeof in);
        memset(out, 0, sizeof out);
        memset(scc_id, 0,sizeof scc_id);
        memset(scc_num, 0, sizeof scc_num);

        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; ++ i){
     
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
        }

        for(int i = 1; i <= n; ++ i)
            if(!dfn[i])
                tarjan(i);

        for(int i = 1; i <= n; ++ i){
     
            for(int j = head[i]; ~j; j = nex[j]){
     
                int k = ver[j];
                if(scc_id[i] != scc_id[k]){
     
                    out[scc_id[i]] ++ ;
                    in[scc_id[k]] ++ ;
                }
            }
        }

        int minv = INF;
        for(int i = 1; i <= scc_cnt; ++ i){
     
            if(!in[i] || !out[i]){
     
                minv = min(minv, scc_num[i]);//找到包含点最少并且出度和入度至少有一个为0的点
            }
        }

        if(scc_cnt == 1){
     
            printf("Case %d: -1\n", cnt);
        }
        else {
     
            printf("Case %d: %lld\n", cnt, 1ll * n * (n - 1) - m - minv * (1ll * n - minv));
        }
    }
    return 0;
}

你可能感兴趣的:(#,强连通分量,缩点,#,有向图的强连通分量)