2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Как перебирать перестановки
Сообщение15.10.2010, 16:47 
Заморожен
Аватара пользователя


18/12/07
8774
Новосибирск
Дано $n \approx 20$, надо перебрать все элементы группы $S_n$ и для каждого кое-что проверить.

Не могу понять, как организовать перебор множества перестановок. Единственное, что пришло в голову --- перебирать всех отображения из $\{ 1, \ldots, n \}$ в $\{ 1, \ldots, n \}$, для каждого проверять инъективность и если отображение оказалось перестановкой, делать с ним то, что нужно. Но уж больно медленно оно работает. Всё-таки $20^{20}$ гораздо больше, чем $20!$ :-(

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 16:59 
Заслуженный участник
Аватара пользователя


13/08/08
14495
а Вам нужно все перебрать или сделать случайную выборку? Их почти квинтиллион. Многовато будет.

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 17:03 
Аватара пользователя


01/04/10
910
Незнаю, правильно ли я Вас понимаю, но вот:

http://en.wikipedia.org/wiki/Permutatio ... rmutations

Так же есть у Кнута в "Конкретной математике", но с ходу найти не получается.

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 17:09 
Заслуженный участник


04/03/09
910
Надо упорядочить все перестановки в лексикографическом порядке (имеется в виду запись перестановки как $(a_1,a_2,...,a_n)$, где $i$-й элемент переходит на место $a_i$), а потом явно указать правило перехода к следующей перестановке. Правило такое:
Находим ближайшую к концу пару элементов, в котором следующий элемент меньше предыдущего (пусть это пара $a_k, a_{k+1},\,\, a_k<a_{k+1}$), теперь переставляем элементы с $k$-го по $n$-ый в таком порядке: на $k$-е место ставим наименьший элемент, больший $a_k$, а остальные располагаем в порядке возрастания.
Начинается перебор перестановок с тождественной, заканчивается перестановкой вида $(a_n,a_{n-1}...a_2,a_1)$
P.S. Если программируете на C++, то в STL есть функция next_permutation(), которая самостоятельно проделывает все вышеописанное.

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 17:17 
Аватара пользователя


01/04/10
910
12d3

Спасибо. Теперь вспомнил источник, вот "Generating All Tuples and Permutations". The Art of Computer Programming. 4, Fascicle 2. (сноска в статье вики, там же про лексикографический порядок)

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 17:24 
Заморожен
Аватара пользователя


18/12/07
8774
Новосибирск
gris в сообщении #362361 писал(а):
а Вам нужно все перебрать или сделать случайную выборку?

Перебрать :-(

На самом деле там всё обозримо... Ещё не дописал, но думаю, будет работать за приемлемое время. Дело в том, что многие перестановки будут отбраковываться по значениям на пяти-шести первых аргументах, так что в дереве надо обходить не квинтильон вершин, а поменьше.

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 17:31 
Заслуженный участник


04/05/09
4587
Профессор Снэйп в сообщении #362378 писал(а):
Дело в том, что многие перестановки будут отбраковываться по значениям на пяти-шести первых аргументах, так что в дереве надо обходить не квинтильон вершин, а поменьше.
Тогда ручная рекурсия. Готовые функции типа next_permutation() как минимум сгенерят все перестановки, которые фильтруются уже потом.
Т.е. для каждого места последовательно выбираете ещё не занятый элемент, и вызываете перебор для следующего места.

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение15.10.2010, 17:36 
Заморожен
Аватара пользователя


18/12/07
8774
Новосибирск
venco в сообщении #362383 писал(а):
Т.е. для каждого места последовательно выбираете ещё не занятый элемент, и вызываете перебор для следующего места.

Ага, так и делаю :-)

 Профиль  
                  
 
 Re: Как перебирать перестановки
Сообщение05.11.2010, 12:50 
Аватара пользователя


30/09/10
119
Нашел у себя вот такую программку.
Это правда для N=6, но думаю, Вам не составит большого труда переделать ее для N=20
Взято из книги В.Липского "Комбинаторика для программистов"
Код:
#include <stdio.h>
#define N 6

main()
{ char s[N+1], t; int i, j, r, k;

for(i=0; i<N; i++) s[i] = '1'+i;
s[N] = '\0';

while(1) {
   printf("%s\n", s);
       // Находим самое правое место, где s[i] < s[i+1]
   for(i=N-1; i>=0 && s[i] > s[i+1]; i--) ;
   if (i<0) break; // Уже получили "654321" - самую старшую перестановку
       // Находим s[j] - наименьший элемент справа от s[i] и больший его
   for(j=N-1; s[i] > s[j]; j--) ;
       // Меняем s[i] <-> s[j]
   t = s[j];
   s[j] = s[i];
   s[i] = t;
       // То, что за "i" - переворачиваем
   for(k=i+1, r=N-1; r > k; k++, r--) {
     t = s[r];
     s[r] = s[k];
     s[k] = t;
   }
}
}

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 9 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group