Ordinamento del pane#6828

Ordinamento del pane (Editoriale)

Il trucco con la paletta esegue la seguente permutazione dei pani:

\begin{pmatrix} a \& b \& c \\ c \& a \& b \end{pmatrix}

Può essere rappresentata come due permutazioni di elementi adiacenti:

(a, b, c) → (a, c, b) → (c, a, b)

Ogni permutazione di elementi adiacenti cambia la parità della permutazione. Di conseguenza, l'operazione indicata sui pani conserva la parità della permutazione.

Ordinare il pane come richiesto dal capo di Michael è possibile solo se le parità delle permutazioni coincidono.

La soluzione lineare del problema si basa sul fatto che due permutazioni hanno la stessa parità se e solo se la parità del numero di cicli in cui si decompongono coincide.

Lemma. Consideriamo il seguente fatto della teoria delle permutazioni:

parità~della~permutazione = (n - numero~di~cicli)~mod~2

Pertanto, per verificare la parità si può:

Se due permutazioni hanno la stessa parità del numero di cicli, allora le loro parità coincidono.

Intuitivamente, ciò deriva dal fatto che ogni ciclo di lunghezza può essere composto da k - 1 scambi di elementi, quindi il numero totale di scambi è pari a

n - numero~di~cicli

Esempio

Nel primo esempio la prima permutazione contiene inversioni, la seconda — inversioni. Il numero di inversioni in entrambe le permutazioni ha la stessa parità.

Decomponiamo le permutazioni in cicli:

Entrambe le permutazioni sono costituite da due cicli, cioè anche il numero di cicli in esse ha la stessa parità.

Nel secondo esempio la prima permutazione contiene inversioni, mentre la seconda — inversioni. Il numero di inversioni in queste permutazioni ha parità diversa.

Decomponiamo le permutazioni in cicli:

La prima permutazione è costituita da cicli, mentre la seconda — da cicli. Pertanto, la parità del numero di cicli in queste permutazioni è diversa.

Implementazione dell'algoritmo

Dichiariamo un array per memorizzare la permutazione.

#define MAX 100010
int a[MAX];

La funzione run percorre un ciclo della permutazione, iniziando dall'indice . Ad ogni passo, passa all'elemento successivo del ciclo secondo la regola pos \to a[pos]. Gli elementi visitati vengono contrassegnati con il valore , per non elaborarli nuovamente. In questo modo, la funzione percorre completamente un ciclo della permutazione e contrassegna tutti i suoi elementi come già visitati.

void run(int pos)
{
  int v;
  while (a[pos] != -1)
  {
    v = a[pos];
    a[pos] = -1;
    pos = v;
  }
}

La funzione parity calcola la parità del numero di cicli nella permutazione , cioè restituisce il numero di cicli modulo . La funzione esamina in sequenza tutte le posizioni dell'array.

int parity(int *a)
{
  int res = 0;

Esaminiamo in sequenza tutte le posizioni dell'array.

  for (int i = 0; i < n; i++)

Se l'elemento non è ancora stato visitato (a[i] \ne -1), ciò significa l'inizio di un nuovo ciclo. In questo caso viene chiamata la funzione , che percorre l'intero ciclo e contrassegna i suoi elementi con il valore .

    if (a[i] != -1) 
    {
      run(i);

Dopo aver percorso il ciclo, il contatore viene incrementato di .

      res++;
    }

Restituiamo la parità del numero di cicli.

  return res % 2;
}

Parte principale del programma. Leggiamo la prima permutazione. Durante la lettura, ogni valore viene decrementato di 1~(a[i]--), per passare dalla numerazione degli elementi da a quella più comoda per il lavoro 0 .. n - 1.

scanf("%d",&n);
for (i = 0; i < n; i++)
  scanf("%d",&a[i]), a[i]--;

Nella variabile calcoliamo la parità del numero di cicli nella permutazione .

p1 = parity(a);

Leggiamo la seconda permutazione. Nella variabile calcoliamo la parità del numero di cicli nella permutazione .

for (i = 0; i < n; i++)
  scanf("%d",&a[i]), a[i]--;
p2 = parity(a);

Confrontiamo le parità del numero di cicli nelle due permutazioni e stampiamo la risposta.

if (p1 == p2) printf("Possible\n");
else printf("Impossible\n");