Участник:ZeRoGerc
Алгоритм Джонсона-Троттера(англ. Johnson-Trotter algorithm) - алгоритм генерации всех перестановок из элементов. Причём любая перестановка отличаются от предыдущей транспозицией двух соседних элементов.
Идея
Сопоставим каждому элементу перестановки направление . Будем указывать направление при помощи стрелок ← ("влево") или →("вправо"). Назовём элемент подвижным, если по направлению стелки стоит элемент меньше его. Например для ←, →, ←, →, ←, подвижными являются элементы 3 и 5. На каждой итерации алгоритма будем искать наибольший подвижный элемент и менять местами с элементом, который стоит по направлению стрелки. После чего поменяем направление стрелок на противоположное у всех элементов больших текущего. Изначально ←, ... ,←
Пример работы алгоритма для n = 3
- ←, ←, ←
- ←, ←, ←
- ←, ←, ←
- →, ←, ←
- ←, →, ←
- ←, ←, →
Псевдокод
//Элементы нумеруются начиная с 1
p = {1, ... , n}
d = {←, ... , ←}
while (true){
print(); // печатаем текущую перестановку
id = -1; // индекс наибольшего подвижного элемента
for i (1 .. n){
if (p[i] - подвижный && (id = -1 || p[i] > p[id]))
id = i;
}
if (id = -1) break; // не нашли подвижного элемента
swap(id); //меняем элемент p[id], d[id] c элементом по направлению стелки
}
Доказательство корректности
Очевидно что требование о том что каждая генерируемая перестановка отличается от предыдущей транспозицией двух соседних элементов выполнено исходя из самого алгоритма. Осталось доказать что таким образом мы сгенерируем все перестановки. Будем использовать обозначениe (a, ←) - элемент с заданным направлением(компонента). Число n в перестановке не является подвижным элементом тогда и толко тогда когда первая компонента перестановки есть (n, ←) или последняя компонента есть (n, →)