HDU 4635 Strongly connected (shrink points, the maximum number of sides can be added to make it still not strongly connected)

A collated collection of algorithm templates: ACM templates


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.

Given a directed graph, find the maximum number of edges that can be added so that the graph is still not a strongly connected graph.

Insert picture description here

Image Source

  • The maximum number of edges that can be added makes this graph still not a strongly connected graph

结论: n ∗ ( n − 1 ) − m − m i n ∗ ( n − m i n v ) n * (n - 1) - m - min * (n - minv) n(n1)mm i n(nm i n v ) (where n is the number of points, m is the number of edges, and minv is the point after the contraction point. At least one of the in-degree and out-degree is 0 and contains the least number of nodes)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
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;
}

Guess you like

Origin blog.csdn.net/weixin_45697774/article/details/108585286