Розглянемо задану послідовність як перестановку чисел від до n - 1. Представимо її у вигляді розкладання на незалежні цикли.
Кожен цикл можна сортувати незалежно від інших. Нехай довжина циклу дорівнює . Тоді, щоб поставити всі елементи цього циклу на свої місця, достатньо виконати k - 1 обмін. Справді, у циклі рівно один елемент можна одразу поставити на правильну позицію, після чого залишається цикл довжини k - 1, і процес продовжується аналогічно.
Переберемо всі індекси від до n - 1. Якщо a_i = i, то елемент вже стоїть на своєму місці, і нічого робити не потрібно. Якщо ж a_i \ne i, значить, ми знайшли цикл, який ще не оброблено.
Далі будемо «розкручувати» цей цикл. Поки a_i \ne i, виконуємо обмін елементів на позиціях та a_i. Після такого обміну елемент a_i стане на своє правильне місце. Повторюючи цю операцію, ми зафіксуємо всі елементи поточного циклу.
Таким чином, щоб знайти мінімальну кількість обмінів, достатньо:
Розкласти перестановку на цикли;
Для кожного циклу довжини додати k - 1 до відповіді.
Приклад
Розглянемо другий приклад. Перестановка (4, 0, 3, 2, 1) розкладається на два цикли:
(4, 1, 0) довжини ;
довжини ;
Для першого циклу знадобиться 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);