Перевертання карт#7538

Перевертання карт (Розбір)

Кожній картинці, зображеній на картах, поставимо у відповідність вершину графа. Кожній карті поставимо у відповідність неорієнтоване ребро, що з'єднує вершини, відповідні зображенням на її сторонах. Отриманий граф може бути незв'язним.

Відповідь на задачу буде possible, якщо в кожній компоненті зв'язності графа міститься не більше одного циклу. Компоненти зв'язності та кількість циклів у них можна визначити за допомогою системи неперетинних множин.

Приклад

Розглянемо чотири карти. Жовтим позначимо сторони карт, що звернені вгору. Кожному ребру графа поставимо у відповідність картинку, якою відповідна карта лежить вгору.

Розглянемо випадок з двома компонентами зв'язності:

Реалізація алгоритму

Визначимо масиви для обробки даних. Масив використовується для системи неперетинних множин. Якщо — представник множини, то has\_cycle[i] містить інформацію про кількість циклів у ній:

#define MAX 50010
int dsu[2*MAX], has_cycle[2*MAX];

Функція Repr повертає представника множини, що містить вершину .

int Repr(int n)
{
  if (n == dsu[n]) return n;
  return dsu[n] = Repr(dsu[n]);
}

Функція Union об'єднує множини, що містять вершини та .

void Union(int x, int y)
{
  int x1 = Repr(x), y1 = Repr(y);

Якщо вершини та вже належать одній компоненті зв'язності (вони мають однакового представника), і при цьому додається ребро , то утворюється ще один цикл. У цьому випадку збільшуємо кількість циклів у представника цієї множини (x_1 — представник та ):

  if (x1 == y1)
    has_cycle[x1]++;

Якщо та належать різним компонентам зв'язності, то виконуємо їх об'єднання, при цьому представник y_1 стає представником об'єднаної множини. У цьому випадку до кількості циклів компоненти з коренем y_1 додаємо кількість циклів компоненти з коренем x_1.

  else
  {
    dsu[x1] = y1;
    has_cycle[y1] += has_cycle[x1];
  }
}

Основна частина програми. Читаємо вхідні дані.

scanf("%d",&tests);
while (tests--)
{
  scanf("%d",&n);

Ініціалізуємо систему неперетинних множин.

  for(i = 1; i <= 2*n; i++)
  {
    dsu[i] = i;
    has_cycle[i] = 0;
  }

Будуємо систему неперетинних множин.

  for (i = 0; i < n; i++) 
  {
    scanf("%d %d",&p,&q);
    Union(p,q);
  }

Перевіряємо, чи існує хоча б одна компонента зв'язності, що містить більше одного циклу.

  for (i = 1; i <= 2*n; i++)
    if (has_cycle[i] > 1) break;

Виводимо відповідь.

  printf("%s\n",((i <= 2 * n) ? "impossible" : "possible"));
}