Avengers#10648

Avengers (Editoriale)

Secondo l'enunciato del problema, è impossibile tornare alla città di partenza dopo aver percorso diverse strade, quindi il grafo delle strade è un grafo diretto aciclico.

Il compito è trovare tre vertici distinti tali che nessun cammino passi per tutti e tre, oppure segnalare che tali vertici non esistono.

Se n < 3, è impossibile scegliere tre città distinte, e la risposta è . D'ora in poi, supponiamo che n \ge 3.

Qualsiasi cammino in un grafo aciclico visita i vertici nell'ordine del loro ordinamento topologico. Pertanto, se un cammino contiene i vertici e , allora uno di essi è raggiungibile dall'altro. Questo porta all'osservazione chiave: se esistono due vertici e tali che nessuno dei due è raggiungibile dall'altro, allora nessun cammino passa per entrambi. Di conseguenza, non esiste nemmeno un cammino che passi per la terna x, y, z, dove è un terzo vertice arbitrario.

Una tale coppia di vertici può essere trovata comodamente usando l'algoritmo di ordinamento topologico di Kahn. Inizialmente, tutti i vertici con grado entrante zero vengono inseriti nella coda. Successivamente, i vertici vengono estratti dalla coda uno a uno e rimossi dal grafo insieme ai loro archi uscenti; i vertici il cui grado entrante diventa zero in seguito a ciò vengono aggiunti alla coda.

Affermazione 1. Se in un certo momento la coda contiene simultaneamente due vertici e , allora non esiste un cammino tra di loro.

Affermazione 2. Se a ogni passo dell'algoritmo la coda contiene esattamente un vertice, allora tutti i vertici del grafo giacciono su un unico cammino.

Quindi, l'algoritmo è il seguente: eseguire l'algoritmo di Kahn e controllare la dimensione della coda prima di ogni estrazione. Non appena essa contiene più di un vertice, prendere due qualsiasi di essi come e , e un qualsiasi altro vertice del grafo come . Se questo momento non si presenta mai, stampare .

Ogni vertice e ogni arco vengono elaborati al più una volta, quindi la complessità temporale dell'algoritmo è O(n + m), e l'utilizzo di memoria è O(n + m).

Esempio

I grafi degli esempi di test hanno la seguente struttura:

Implementazione dell'algoritmo

Dichiariamo le strutture dati. Il grafo di input è rappresentato dalla lista di adiacenza , e i gradi entranti dei vertici sono memorizzati nell'array InDegree.

vector<vector<int> > g;
vector<int> InDegree;
deque<int> q;

Leggiamo i dati in input.

scanf("%d %d", &n, &m);
g.resize(n + 1);
InDegree.resize(n + 1);
for (i = 0; i < m; i++)
{
  scanf("%d %d", &a, &b);
  g[a].push_back(b);

Per ogni arco , incrementiamo InDegree[b] di .

  InDegree[b]++;
}

Tutti i vertici con grado entrante zero vengono aggiunti alla coda .

for (i = 1; i < InDegree.size(); i++)
  if (InDegree[i] == 0) q.push_back(i);

I tre vertici cercati sono memorizzati nelle variabili e .

x = y = -1;

Continuiamo a eseguire l'algoritmo finché la coda non è vuota.

while (!q.empty())
{

Se la coda contiene più di un vertice nello stesso momento, significa che la soluzione è stata trovata.

  if (q.size() > 1)
  {
    x = q[0];
    y = q[1];
    break;
  }

Estraiamo il vertice dalla coda — esso diventerà il vertice corrente nell'ordine topologico.

  v = q.front(); q.pop_front();

Rimuoviamo dal grafo tutti gli archi della forma (v, to). Per ciascuno di tali archi, diminuiamo il grado entrante del vertice . Se il grado entrante di diventa zero, lo aggiungiamo alla coda.

  for (int to : g[v])
  {
    InDegree[to]--;
    if (InDegree[to] == 0) q.push_back(to);
  }
}

L'algoritmo di Kahn è completato. Se il valore di è ancora , significa che non esiste alcuna soluzione.

if (x == -1)
  printf("-1\n");
else
{

Se esiste una soluzione, scegliamo come il più piccolo vertice diverso da e .

  z = 1;
  while (z == x || z == y) z++;
    printf("%d %d %d\n", x, y, z);
}