P4819 [Selección de la ciudad de Zhongshan] Tarjan SCC

Título

Portal P4819 [Selección de la ciudad de Zhongshan] Juego de asesinato

respuesta

Si xxxyyy , luego dexxx y y Conecte y a un borde dirigido para obtener un gráfico dirigido. La observación encontró que si hay un anillo, simplemente elija un punto en el anillo, entonces hay1 / N 1 / NLa probabilidad de 1 / N es el asesino; de lo contrario, la identidad del siguiente nodo se puede obtener hasta que se encuentre el último nodo del anillo o el asesino.

Entonces usa T arjan TarjanT a r j a n algoritmo para resolverSCC SCCS C C , reduce el mapa y obtén unDAG DAGD A G . Para en grado0 00 puntoxxx , obviamente no se puede obtenerxxcomprobando otros nodosLa identidad de x , entonces este nodo necesita ser verificado. Para grados superiores a0 00 nodoxxx , el nodoyycuyo orden topológico es menor de lo que puede sery para obtenerxxidentidad de x . Entonces, el nodo a verificar essum = ∑ x ∈ G [indeg [x] = 0] sum = \ sum \ limits_ {x \ in G} \ big [indeg [x] = 0 \ big]s u m=x GΣ[ e n d e g [ x ]=0 ]

Pero el algoritmo aún no es del todo correcto, porque para obtener la identidad de una persona, existe un tercer método además de comprobar y comprender de las personas que lo conocen: el método de eliminación . Si solo el último nodo del gráfico no conoce su identidad, debe inferirse mediante el método de eliminación. Entonces necesitas determinar que el grado es 0 0Entre los puntos de 0 , ¿hay un nodo donde se pueda aplicar el método de eliminación?

En primer lugar, el SCC SCC correspondiente a dicho nodoEl número de nodos en S C C es1 11 , de lo contrario, no se puede juzgar la identidad de otros nodos en el anillo; en segundo lugar, tal nodoxxx si hay un borde saliente(x, y) (x, y)( x ,y),则 y y y debe tener uno de otros nodoszzBorde entrante de z , de lo contrarioyyNo se puede entender la identidad de y . Para juzgar simplemente si existe tal lado de entrada, el establecimiento deDAG DAGCuando D A G , los bordes de conexión entre los nodos se deduplican, es decir, el grado interno del nodo se puede usar para indicar cuántos nodos diferentes pueden actualizar el nodo.

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005, maxm = 300005;
int N, M, num, low[maxn], dfn[maxn];
int tot, head[maxn], to[maxm], nxt[maxm];
int tot_c, hc[maxn], tc[maxm], nc[maxm];
int top, st[maxn], scc, sc[maxn], in[maxn], sz[maxn];
bool ins[maxn], vs[maxn];

inline void add(int x, int y) {
    
     to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }

inline void add_c(int x, int y) {
    
     tc[++tot_c] = y, nc[tot_c] = hc[x], hc[x] = tot_c; }

void tarjan(int x)
{
    
    
    low[x] = dfn[x] = ++num;
    st[++top] = x, ins[x] = 1;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[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 (low[x] == dfn[x])
    {
    
    
        ++scc;
        int y;
        do
        {
    
    
            y = st[top--], ins[y] = 0;
            sc[y] = scc, ++sz[scc];
        } while (y != x);
    }
}

int main()
{
    
    
    scanf("%d%d", &N, &M);
    for (int i = 1, x, y; i <= M; ++i)
        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 = nxt[j])
        {
    
    
            int x = sc[i], y = sc[to[j]];
            if (x != y && !vs[y])
                vs[y] = 1, add_c(x, y), ++in[y];
        }
        for (int j = head[i]; j; j = nxt[j])
            vs[sc[to[j]]] = 0;
    }
    int sum = 0, lst = 0;
    for (int i = 1; i <= scc; ++i)
        if (!in[i])
        {
    
    
            ++sum;
            if (!lst && sz[i] == 1)
            {
    
    
                bool f = 1;
                for (int j = hc[i]; j; j = nc[j])
                    f &= in[tc[j]] > 1;
                if (f)
                    --sum, lst = 1;
            }
        }
    printf("%.6f\n", (double)(N - sum) / N);
    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/neweryyy/article/details/115034377
Recomendado
Clasificación