[Все темы по перестановкам]        
      
Теория:       
1) Липский. Комбинаторика для программистов. 1988       
2) Меньшиков. Олимпиадные задачи по программированию. 2006.
Рассмотрим две задачи:      
1) Рекурсивный способ генерации всех перестановок в лексикографическом порядке.
2) Рекурсивный способ генерации всех перестановок в антилексикографическом порядке.
      
Для начала разберемся, что такое лексико- и антилексико-графические порядки.
Начальная перестановка: {1, 2, 3}
  1) Рекурсивный способ генерации всех перестановок в лексикографическом порядке.
2) Рекурсивный способ генерации всех перестановок в антилексикографическом порядке.
Для начала разберемся, что такое лексико- и антилексико-графические порядки.
Начальная перестановка: {1, 2, 3}
| № | Лексикографический | Антилексикографический | 
| 0 | 1 2 3 | 1 2 3 | 
| 1 | 1 3 2 | 2 1 3 | 
| 2 | 2 1 3 | 1 3 2 | 
| 3 | 2 3 1 | 3 1 2 | 
| 4 | 3 1 2 | 2 3 1 | 
| 5 | 3 2 1 | 3 2 1 | 
Напомним, что лексикографический порядок – это порядок слов, который используется в словарях.
Слово A меньше слова B, если первые i символов слов равны, а символ A[i+1] < B[i+1]. Отсюда вытекает следствие, что если слово А является началом слова B, то A < B.
Антилексикографический порядок отличается от лексикографического только тем, что сравнение символов идет справа налево.
Слово A меньше слова B, если последние i символов равны, а символ A[i-1] < B[i-1]. Также следует, что если слово B заканчивается на слово A, то A < B.
Практика:
Решим задачу 2B-Перестановки из задачника Федора Меньшикова двумя рассматриваемыми способами.
Как можно было заметить, оба порядка начинаются с минимальной перестановки {1, 2, 3} и заканчивается максимальной {3, 2, 1}.
1) Генерация всех перестановок в лексикографическом порядке.
                - int n; 
- vector<int> p; 
- vector<bool> used; 
- string str; 
- ... 
- void lex(int pos) 
- { 
-   if (pos == n) { 
-     for (int i=0;i<n;i++) 
-       cout<<str[p[i]]; 
-     cout<<endl; 
-     return; 
-   } 
-   for (int i=0;i<n;i++) { 
-     if (!used[i]) { 
-       used[i] = true; 
-       p[pos] = i; 
-   
-       lex(pos+1); 
-       
-       p[pos] = 0; // debug only 
-       used[i] = false; 
-     } 
-   } 
- } 
* This source code was highlighted with Source Code Highlighter.Рекурсивная функция lex(n) генерируется все перестановки из алфавита {0,1,..n-1} длиной n и хранит текущую перестановку в массиве p. Если номер текущей позиции pos == n, тогда сгенерирована следующая перестановка.        
[Решение]        
        
2) Генерация всех перестановок в антилексикографическом порядке          
Решение полностью идентично, за исключением того, что перестановка формируется с конца         
[Решение]
 
 
Товарищ, прога сочетания генирирует а не перестановки !
ОтветитьУдалитьЕсли можете, поясните свою точку зрения.
ОтветитьУдалитьСо своей стороны могу добавить, что для генерации сочетаний необходимо множество из N элементов и K (K<=N) элементов, которые необходимо выбрать из N. Пусть мы имеем множество {1,2,3} N = 3. Допустим K=2.
Если мы говорим о сочетаниях, то далее перечислены все сочетания из N по K:
A = {1,2}
B = {1,3}
C = {2,3}
Проверяем по формуле С(n,k) = 3!/(2!*1!) = 3. Следовательно больше сочетаний нет.
Сочетание D = {2,1} не будет входить в исходный набор, т.к. оно равно сочетанию A. Поэтому помним, что для сочетаний порядок элементов не важен. Если же важен порядок, то тут уже речь идет о размещениях.
Видимо предыдущий оратор намекал на то, что сложность вашего алгоритма - pow(N, N), в то время как для оптимальный алгоритм должен иметь сложность fact(N).
ОтветитьУдалитьПредыдущий оратор не знает разницы между сочетаниями и перестановками. И если несложно поясните оценку pow(N,N)
УдалитьЭтот комментарий был удален автором.
УдалитьУ вас на каждом рекурсивном шаге цикл пробегает от 0...n-1, for (int i=0;i<n;i++), если вы будете запускать его с текущей позиции pos, то будет факториал, вот пример: http://www.cyberforum.ru/cpp-beginners/thread444081.html
УдалитьХотя перестановки не будут упорядоченны лексикографически