Получить все перестановки чисел 1..n (то есть последовательности  длины  n, в которые каждое из чисел 1..n входит по одному разу).

Решение. Перестановки будем  хранить  в  массиве  x[1],...,x[n]  и  печатать в лексикографическом порядке. (Первой при этом будет перестановка <1 2...n>, последней-<n...2 1>.)  Для  составления  алгоритма  перехода к следующей перестановке зададимся
  вопросом: в каком случае k-ый член перестановки можно увеличить, не меняя предыдущих? Ответ: если он меньше какого-либо из следующих членов (членов с номерами больше k). Мы  должны  найти  наибольшее  k,  при  котором  это  так,  т. е. такое k, что x[k]<x[k+1] > ... > x[n]. После  этого  x[k]  нужно  увеличить  минимальным  возможным способом, т. е. найти среди x[k+1], ..., x[n] наименьшее число, большее его. Поменяв x[k] с ним, остается расположить числа с номерами k+1, ..., n  так,  чтобы  перестановка была наименьшей, то есть в возрастающем порядке. Это облегчается тем, что они уже расположены в убывающем порядке.

Алгоритм перехода к следующей перестановке.

  {<x[1],...,x[n-1], x[n]> <> <n,...,2, 1>.}
  k:=n-1;
  {последовательность справа от k убывающая: x[k+1] >...> x[n]}
 
while x[k] > x[k+1] do begin
  | k:=k-1;
  end;
  {x[k] < x[k+1] > ... > x[n]}
  t:=k+1;
  {t <=n, x[k+1] > ... > x[t] > x[k]}
   while (t < n) and (x[t+1] > x[k]) do begin
   | t:=t+1;
   end;
   {x[k+1] > ... > x[t] > x[k] > x[t+1] > ...
> x[n]}
   ... обменять x[k] и x[t]
   {x[k+1] > ... > x[n]}
   ... переставить участок x[k+1] ... x[n] в обратном порядке

Замечание. Программа имеет знакомый  дефект:  если  t  =  n,  то x[t+1] не определено.


2009-12-04 • Просмотров [ 2713 ]