17 декабря 2011 г.

Реализация генерации всех циклических перестановок чисел от 1 до n.

Реализация генерации всех циклических перестановок чисел от 1 до n.
Циклические перестановки чисел от 1 до n - такие перестановки чисел  от 1 до n, при которых значение текущего числа соотносится с его текущей порядковой позицией таким образом, что она равна числу, стоявшему на позиции, с которой был осуществлён переход на текущую позицию, и при которых такие переходы можно совершать сколько угодно раз без изменения порядка расположения чисел.
Пример.
n = 3.
Изначально последовательность инициализируется, как 1 2 3.
Тогда все циклические перестановки от 1 до 3:
  • 2 3 1
  • 3 1 2

Перестановка 2 3 1 является циклической по следующей причине. Рассмотрение начинается с первой позиции. На ней находится число 2. Поэтому далее следует переход к позиции 2, на которой стоит число 3. Следовательно, происходит переход к позиции 3. На третей позиции расположено число 1, что означает переход к первой позиции. Таким образом, цикл замкнулся, и, если переходы продолжать, то каждая итерация будет одинакова и число проходов по перестановке будет неограниченно (Рисунок 1). Аналогично обосновывается цикличность перестановки 3 1 2.

Рисунок 1. Схема циклической перестановки 2 3 1.


Ниже будет представлена программа на языке программирования C++, реализующая генерацию и вывод всех циклических перестановок чисел от 1 до n.


#include <iostream>

using namespace std;



int X[100]; //Массив с N подряд идущими числами
int N; //Число элементов для перестановок

//Перемена мест двух соседних элементов массива
void Swap (int a, int b)
{
    int t = X[a];
    X[a] = X[b];
    X[b] = t;
}

/*Проверка на наличие одного цикла в числе*/
bool iscorrect()
{
int a = X[0]; //Переменная для сравнения текущего элемента с первым
int size = 0; //Счётчик достигаемости
do //Пока не достигнут первый элемент сравнивать с ним последующие
{
a = X[a-1]; //Получение текущего элемента
size++; //Увеличить size
}
while(a != X[0]); //Сравнение текущего элемента с начальным
if (size < N) //Если size не достигает величины N, то цикла нет
{
return false;
}
else //size достиг величины N, значит имеет место цикл
{
return true;
}
}

/*Генерация всех перестановок*/
void Generate (int k)
{
    if (k == N) //Одна перестановка завершена, вывод
    {
if (iscorrect()) //Если есть циклическая престановка, то вывод
        {
        
for (int i=0; i < N; i++)
{
std::cout << X[i] << " "; //Вывод каждого элемента через " "
}
std::cout << "\n"; //Вывод каждой перестановки через строку
}
    }
    else //Перестановка ещё не завершена, обработка элементов
    { 
        //Перемещение элементов для построения перестановки
        for (int j = k; j < N; j++)
        {
            Swap(k , j); //Поменять, если необходимо, элементы местами
            Generate(k + 1); //Рекурсивный вызов (для следующего элемента)
            Swap(k , j); // Финальное перемещение
        }
    }
}


/*Главная часть программы*/
int main()
{
    //Пользовательские инструкции
    std::cout << "Input N value please.\n";
    std::cout << "N = ";
    std::cin >> N; // Считывание введённого N
    //Инициализация массива с N подряд идущими числами для перестановок
    for (int i = 0; i < N; i++)
    {
        X[i] = i + 1;
    }
    //Вызов функции генерации всех циклических перестановок всех чисел от 1 до N
    Generate(0);
}

Массив чисел для перестановки инициализируется подряд идущими значениями от 1 до n. Затем вызывается функция Generate(0); для генерации перестановок. В случае, если элементы нуждаются в перемене местами, вызывается функция Swap(k , j);. Далее происходит рекурсивный вызов функции Generate (k + 1) и переход к работе со следующим элементом. Завершается и выводится на экран одна перестановка, когда k становится равным N и в случае, если имеет место циклическая перестановка. Наличие циклической перестановки определяется булевой функцией bool iscorrect(). Эта функция сравнивает в цикле разные элементы с первым и увеличивает счётчик. Если счётчик достигает N, то цикл в последовательности есть. Далее обрабатываются остальные варианты перестановок.
Стоит отметить, что совокупная сложность алгоритма получения всех циклических перестановок чисел от 1 до n составляет n!.