HDU 4635 Fuertemente conectado (puntos de contracción, se puede agregar el número máximo de lados para que aún no esté fuertemente conectado)

Una colección recopilada de plantillas de algoritmos: plantillas de ACM


HDU 4635 Fuertemente conectado

Da un gráfico dirigido simple con N nodos y M aristas. Por favor dígame el número máximo de bordes que puede agregar para que el gráfico siga siendo un gráfico dirigido simple. Además, después de agregar estos bordes, este gráfico NO debe estar fuertemente conectado.
Un gráfico dirigido simple es un gráfico dirigido que no tiene múltiples aristas ni bucles de gráfico.
Un dígrafo fuertemente conectado es un gráfico dirigido en el que es posible llegar a cualquier nodo comenzando desde cualquier otro nodo atravesando los bordes en la (s) dirección (es) en la que apuntan.

Entrada
La primera línea de la fecha es un número entero T, que es el número de casos de texto.
Luego siguen T casos, cada caso comienza con dos números N y M, 1 <= N <= 100000, 1 <= M <= 100000, que representa el número de nodos y el número de aristas, luego siguen M líneas. Cada línea contiene dos números enteros xey, lo que significa que hay una arista de xay.

Salida
Para cada caso, debe generar el número máximo de bordes que puede agregar.
Si el gráfico original está fuertemente conectado, solo dé salida a -1.

Dado un gráfico dirigido, encuentre el número máximo de aristas que se pueden agregar para que el gráfico todavía no sea un gráfico fuertemente conectado.

Inserte la descripción de la imagen aquí

Fuente de imagen

  • El número máximo de bordes que se pueden agregar hace que este gráfico aún no sea un gráfico fuertemente conectado

结论 :n ∗ (n - 1) - m - min ∗ (n - minv) n * (n - 1) - m - min * (n - minv)norte( n-1 )-metro-m i n( n-m i n v ) (donde n es el número de puntos, m es el número de aristas y minv es el punto después del punto de contracción. Al menos uno de los grados de entrada y salida es 0 y contiene el menor número de nodos)

#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;
}

Supongo que te gusta

Origin blog.csdn.net/weixin_45697774/article/details/108585286
Recomendado
Clasificación