Участник:ZeRoGerc — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Доказательство корректности)
(Псевдокод)
Строка 14: Строка 14:
 
== Псевдокод ==
 
== Псевдокод ==
 
<code>
 
<code>
  //Элементы нумеруются начиная с 1  
+
  <font color=darkgreen> //Элементы нумеруются начиная с 1 </font color=darkgreen>
 
  p = {1, ... , n}
 
  p = {1, ... , n}
 
  d = {←, ... , ←}
 
  d = {←, ... , ←}
  while (true){
+
  '''while''' (true){
   print(); // печатаем текущую перестановку
+
   print(); <font color=darkgreen>// печатаем текущую перестановку</font color=darkgreen>
   id = -1; // индекс наибольшего подвижного элемента
+
   id = -1; <font color=darkgreen>// индекс наибольшего подвижного элемента </font color=darkgreen>
   for i (1 .. n){
+
   '''for''' i (1 .. n){
       if (p[i] - подвижный && (id = -1 || p[i] > p[id]))
+
       '''if''' (p[i] - подвижный) '''and''' ((id = -1) '''or''' (p[i] > p[id]))
         id = i;
+
         id = i
 
   }
 
   }
   if (id = -1) break; // не нашли подвижного элемента
+
   '''if''' (id = -1) '''break''' <font color=darkgreen>// не нашли подвижного элемента</font color=darkgreen>
   swap(id); //меняем элемент p[id], d[id] c элементом по направлению стелки  
+
   swap(id) <font color=darkgreen>//меняем элемент p[id], d[id] c элементом по направлению стелки</font color=darkgreen>
 
  }
 
  }
 
</code>
 
</code>

Версия 11:23, 28 ноября 2014

Алгоритм Джонсона-Троттера(англ. Johnson-Trotter algorithm) - алгоритм генерации всех перестановок из [math]n[/math] элементов. Причём любая перестановка отличаются от предыдущей транспозицией двух соседних элементов.

Идея

Сопоставим каждому элементу перестановки [math]p[i][/math] направление [math]d[i][/math]. Будем указывать направление при помощи стрелок ("влево") или ("вправо"). Назовём элемент подвижным, если по направлению стелки стоит элемент меньше его. Например для [math] p = \{1, 3, 2, 4, 5\},\;d = \{[/math]←, →, ←, →, ←[math]\}[/math], подвижными являются элементы 3 и 5. На каждой итерации алгоритма будем искать наибольший подвижный элемент и менять местами с элементом, который стоит по направлению стрелки. После чего поменяем направление стрелок на противоположное у всех элементов больших текущего. Изначально [math] p = \{1, ... ,n\},\;d = \{[/math]←, ... ,←[math]\}[/math]

Пример работы алгоритма для n = 3

  • [math] p = \{1, 2, \textbf{3}\}\;\;\;d = \{[/math]←, ←, ←[math]\}[/math]
  • [math] p = \{1, \textbf{3}, 2\}\;\;\;d = \{[/math]←, ←, ←[math]\}[/math]
  • [math] p = \{3, 1, \textbf{2}\}\;\;\;d = \{[/math]←, ←, ←[math]\}[/math]
  • [math] p = \{\textbf{3}, 2, 1\}\;\;\;d = \{[/math]→, ←, ←[math]\}[/math]
  • [math] p = \{2, \textbf{3}, 1\}\;\;\;d = \{[/math]←, →, ←[math]\}[/math]
  • [math] p = \{2, 1, 3\}\;\;\;d = \{[/math]←, ←, →[math]\}[/math]

Псевдокод

 //Элементы нумеруются начиная с 1  
p = {1, ... , n}
d = {←, ... , ←}
while (true){
  print(); // печатаем текущую перестановку
  id = -1; // индекс наибольшего подвижного элемента 
  for i (1 .. n){
     if (p[i] - подвижный) and ((id = -1) or (p[i] > p[id]))
       id = i
  }
  if (id = -1) break // не нашли подвижного элемента
  swap(id) //меняем элемент p[id], d[id] c элементом по направлению стелки 
}

Доказательство корректности

Очевидно что требование о том что каждая генерируемая перестановка отличается от предыдущей транспозицией двух соседних элементов выполнено исходя из самого алгоритма. Осталось доказать, что таким образом мы сгенерируем все перестановки. Будем использовать обозначениe [math](a,[/math][math])[/math] - элемент с заданным направлением(компонента).

Утверждение:
Число [math]n[/math] в перестановке не является подвижным элементом тогда и толко тогда когда первая компонента перестановки есть [math](n,[/math][math])[/math] или последняя компонента есть [math](n,[/math][math])[/math]