Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
АиПА / Лекции / 6_Комбинаторные задачи и вычисл на множествах.doc
Скачиваний:
16
Добавлен:
07.02.2016
Размер:
150.53 Кб
Скачать

4. Получение полных наборов комбинаторных объектов. Перестановки

Получение полных наборов комбинаторных объектов (КО) важно для решения многих задач дискретного анализа. Примером могут служить задачи оптимизации на дискретных множествах, при решении которых используются полные наборы КО.

При использовании полных наборов КО используются два вида процедур:

- процедуры, которые генерируют все КО, составляющие полный набор;

- процедуры, которые при каждом вызове выдают очередной КО.

Число перестановок n элементов равно:

Nprm(n) = n! = 123 ... n .

Перестановки

Рекурсивная процедура permuts генерирует и выводит на экран все перестановки элементов массива A.

int P; // номер очередной перастановки

void permuts(int* A, int n, int k) // k – номер рекурсивного вызова

{ int i,j;

for (i = k; i < n; i++)

{ swp(A[k], A[i]);

if (i !=k || k == 0) { P++; printf("%2d ",P);

for (j = 0; j < n; j++) printf("%2d ",A[j]); puts("");

}

if (k < n-2) permuts(A, n, k+1);

swp(A[k], A[i]);

}

}

Пример использования процедуры permuts:

Void main()

{ int x[5];

for (int i = 0; i < 5; i++) x[i] = i+1;

permuts(x, 5, 0);

}

Функция next_permut при каждом вызове формирует очередную перестановку элементов массива p и возвращает ее номер. При исчерпании всех подстановок функция возвращает 0.

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

p = {4,2,3,5,6,1}.

Просматриваем элементы последовательности справа налево, начиная с предпоследнего. Находим первый из них, который меньше последующего. В нашем примере это элемент 3. Среди элементов, которые расположены справа от него находим наименьший элемент, который, в то же время, больше элемента 3. Таким явялется элемент 5. Меняем местами элементы 3 и 5. Получаем:

p = {4,2,5,3,6,1}.

Теперь все элементы, которые находятся правее, чем 5, упорядочиваем по возрастанию. Получаем окончательно:

p = {4,2,5,1,3,6}.

Следующая перестановка получена.

Int next_permut(int* p, int n)

{ static int M=0;

M++; if (M == 1) return M;

int i, im, j, m;

for (i = n-2; i >= 0; i--)

{ if (p[i] < p[i+1]) { m = p[i+1]; im = i+1;

for (j = i+1; j < n; j++)

if (p[j] > p[i] && p[j] < m) { m = p[j]; im = j; }

break;

}

}

if (i < 0) return 0;

swp(p[i], p[im]);

sortup(i+1, n-1, p);

return M;

}

Пример использования функции next_permut:

Void main()

{ int i, N, A[5];

for (i = 0; i < 5; i++) A[i] = i+1;

while (N = next_permut(A, 5)) { printf("%3d ",N);

for (i = 0; i < 5; i++) printf("%2d ", A[i]);

puts("");

}

pause;

}

5. Подмножества

Получение полного набора некоторых комбинаторных объектов является важной задачей дискретных вычислений. Например, решение многих задач дискретной оптимизации почти всегда связано с перебором объектов некоторого полного набора. Число r-элементных подмножеств из n-элементного множества равно числу сочетаний:

.

Количество всех подмножеств n-элементного множества равно:

.

Алгоритм получения полного набора подмножеств представим в виде программы на языке С++.

Используется алгоритм перебора бинарных кодов, представляющих искомые подмножества. Бинарный код подмножества представлен массивом типа unsigned char, при этом в 1 байт – элемент массива записывается 1 бит бинарного кода. Однако эту же идею можно реализовать и для носителя подмножества типа битового вектора.

Множество представлено битовым вектором d: