Ordinamento topologico unico#10652

Ordinamento topologico unico (Editoriale)

Utilizziamo l'algoritmo di Kahn. Ricordiamo che esso mantiene una coda di vertici con grado entrante zero – esattamente i vertici che possono essere posizionati nella prossima posizione dell'ordinamento topologico. Ad ogni iterazione, un vertice viene estratto dalla coda e aggiunto alla risposta, e i gradi entranti di tutti i suoi vicini vengono diminuiti di . I vertici il cui grado entrante diventa zero vengono aggiunti alla coda.

Osservazione chiave: l'ordinamento topologico è unico se e solo se la coda contiene esattamente un vertice prima di ogni estrazione.

Complessità. Ogni vertice e ogni arco vengono elaborati una sola volta, quindi il tempo di esecuzione è O(n + m).

Esempio

I grafi dei casi di test sono i seguenti:

Nel primo esempio l'ordinamento topologico è unico:

Nel secondo esempio ci sono due possibili ordinamenti topologici:

Implementazione dell'algoritmo

Memorizziamo il grafo di input in una lista di adiacenza . I gradi entranti dei vertici sono memorizzati nell'array InDegree. Dichiariamo la coda .

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

Leggiamo il grafo di input. Per ogni arco incrementiamo InDegree[b] di .

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);
  InDegree[b]++;
}

Aggiungiamo alla coda tutti i vertici con grado entrante zero.

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

Impostiamo flag = 1 se l'ordinamento topologico è unico.

flag = 1;

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

while (!q.empty())
{

Se la coda contiene più di un vertice, allora l'ordinamento topologico non è unico.

  if (q.size() > 1) flag = 0;

Estraiamo il vertice corrente dalla coda.

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

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

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

A seconda del valore di , stampiamo la risposta.

if (flag == 1)
  printf("YES\n");
else
  printf("NO\n");