Сортування від 0 до n - 1#8636

Сортування від 0 до n - 1 (Розбір)

Розглянемо задану послідовність як перестановку чисел від до n - 1. Представимо її у вигляді розкладання на незалежні цикли.

Кожен цикл можна сортувати незалежно від інших. Нехай довжина циклу дорівнює . Тоді, щоб поставити всі елементи цього циклу на свої місця, достатньо виконати k - 1 обмін. Справді, у циклі рівно один елемент можна одразу поставити на правильну позицію, після чого залишається цикл довжини k - 1, і процес продовжується аналогічно.

Переберемо всі індекси від до n - 1. Якщо a_i = i, то елемент вже стоїть на своєму місці, і нічого робити не потрібно. Якщо ж a_i \ne i, значить, ми знайшли цикл, який ще не оброблено.

Далі будемо «розкручувати» цей цикл. Поки a_i \ne i, виконуємо обмін елементів на позиціях та a_i. Після такого обміну елемент a_i стане на своє правильне місце. Повторюючи цю операцію, ми зафіксуємо всі елементи поточного циклу.

Таким чином, щоб знайти мінімальну кількість обмінів, достатньо:

Приклад

Розглянемо другий приклад. Перестановка (4, 0, 3, 2, 1) розкладається на два цикли:

Для першого циклу знадобиться 3 - 1 = 2 обміни, для другого 2 - 1 = 1 обмін. Таким чином, загальна мінімальна кількість обмінів дорівнює 2 + 1 = 3.

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

Вхідну перестановку зберігатимемо в масиві . Виконані обміни зберігаємо в масиві .

vector<int> a;
vector<pair<int, int> > ans;

Читаємо вхідну перестановку.

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

Якщо a_i \ne i, то обробляємо цикл, якому належить елемент a_i, виконуючи необхідні обміни. Кількість виконаних обмінів підраховуватимемо у змінній .

for (i = 0; i < n; i++)
  while (a[i] != i)
  {
    ans.push_back(make_pair(i, a[i]));
    swap(a[i], a[a[i]]);
    cnt++;
  }

Виводимо кількість обмінів , а потім самі виконані обміни.

printf("%d\n", cnt);
for (i = 0; i < ans.size(); i++)
  printf("%d %d\n", ans[i].first, ans[i].second);