Madrigueras (OmegaUp)

Link al problemaMadrigueras

Dificultad: Medio

Problema:
El principal problema radica en encontrar una manera correcta de representar la información que se nos da, la manera más sencilla es representar cada camino hecho por una suricata como una arista unidireccional. Por lo tanto tenemos $N$ ($1 ≤ N ≤ 10^5$) nodos y $M$ aristas entre ellos.

Como ejemplo de lo anterior, veamos cómo representaríamos el caso de prueba de diversas maneras:
Entrada: Representación: Explicación:
5 4
1 2
3 2
4 5
4 5
Las aristas rojas nos indican que la suricata 3 creó un camino hacia el cuarto 2, mientras que la suricata 2 creó un camino hacia el cuarto 1.
Las aristas azules nos indican que la suricata 3 creó un camino hacia el cuarto 2, mientras que la suricata 1 también creó un camino hacia el cuarto 2 y así sucesivamente.

En la imagen anterior también se puede observar algo peculiar, y es que para cada componente conexa solo existen dos posibilidades válidas para colocar las aristas (de acuerdo al problema): Cada componente con $V$ nodos debe tener a lo más $V$ aristas, ya que de tener más implicaría que una suricata construyó más de un camino, lo cual no es posible.

Para responder al problema necesitamos conocer de cuantas maneras se pueden colocar las aristas, dadas las condiciones establecidas anteriormente. Para una componente conexa de $N$ nodos con $N - 1$ aristas (un árbol), podemos elegir cualquiera de los $N$ nodos como la raíz, dejandonos con un total de $N$ maneras de formarlo. Mientras que para una componente con $N$ aristas (un grafo cíclico) solamente tenemos $2$ maneras.

Solución:
Dado que el problema implica componentes conexas, emplearemos la estructura disjoint-set para llevar un registro de ellas. También sabemos que necesitamos conocer la cantidad de nodos y aristas dentro de una misma componente, para lo cual podemos emplear alguna clase de búsqueda en grafos, sin embargo, también podemos modificar las operaciones del disjoint-set para llevar el conteo de los nodos y aristas; la modificación propuesta radica en que a cada llamada a la función unir siempre sumémos una arista a nuestra componente, sin importar si dicha unión representaría un ciclo.

Por último, la respuesta esperada se obtiene de multiplicar las formas de ordenar las aristas para cada componente y aplicarles la operación módulo, ya que el resultado puede ser bastante grande.

Complejidad: $O(M)$, donde $M$ es el número de aristas especificadas en el problema

Código (C++) y pseudocódigo:
Implementación de disjoint-set (C++):
Definiremos un arreglo V, donde V[i] es la cantidad de vértices que tiene la componente i-ésima. Definiremos un arreglo E, donde E[i] es la cantidad de aristas que tiene la componente i-ésima. Definiremos un arreglo G, donde G[i] es el identificador de la componente i-ésima.
// Join function
void join(int i, int j){
 int pi = root(i);
 int pj = root(j);
 E[pi] += 1; // Siempre sumar una arista a nuestra componente
 if(pi != pj){
  G[pj] = G[pi];
  V[pi] += V[pj];
  E[pi] += E[pj];
 }
}

// Root function
int root(int n){
 if(G[n] != n) 
  G[n] = root(G[n]);
 return G[n];
}

Solución al problema (pseudocódigo):
Sea K un arreglo con todos los identificadores de cada componente conexa:
var res := 1
foreach i in K
 if E[i] = V[i]
  res := res * 2
 elsif E[i] = V[i] - 1
  res := res * N
 else
  res := 0
end foreach
print res mod 1000000007

No hay comentarios on "Madrigueras (OmegaUp)"

Leave a Reply