Одним із прямих способів є рекурсивна процедура, яка робить наступне для кожного виклику. Вхід до процедури - це список вже вибраних пар і список усіх пар.
- Обчисліть найменше число, яке ще не охоплено списком введення. Для першого виклику це, звичайно, буде 0, оскільки не було обрано жодної пари.
- Якщо всі цифри вкриті, у вас є правильна комбінація, роздрукуйте її та поверніть попередній крок. В іншому випадку найменше число, яке не буде виявлено, - це ціль, на яку ми будемо прагнути.
- Шукайте через пари, які шукають спосіб покрити цільове число. Якщо його немає, то просто поверніться до попереднього рівня рекурсії.
- Якщо є спосіб прикрити цільове число, виберіть перший спосіб і рекурсивно зателефонуйте всю процедуру ще раз, при цьому щойно вибрану пару додайте до списку обраних пар.
- Коли це повернеться, шукайте наступний спосіб прикрити цільове число парою, не перекриваючи раніше вибрану пару. Якщо ви знайдете його, виберіть його і знову рекурсивно зателефонуйте на наступну процедуру.
- Продовжуйте кроки 4 та 5, поки не буде більше способів покрити цільове число. Пройдіть весь список пар. Коли більше немає правильного вибору, поверніться до попереднього рівня рекурсії.
Спосіб візуалізації цього алгоритму полягає у дереві, шляхи якого є послідовностями пар, що не перетинаються. Перший рівень дерева містить усі пари, які містять 0. Для наведеного вище прикладу дерево є
Корінь
|
----------------
| | |
(0,1) (0,2) (0,3)
| | |
(2,3) (1,3) (1,2)
У цьому прикладі всі шляхи через дерево насправді дають правильні колекції, але, наприклад, якщо ми залишили пару (1,2), то найправіший шлях мав би лише один вузол і відповідав би пошуку на етапі 3, якщо це не вдалося.
Алгоритми пошуку цього типу можуть бути розроблені для багатьох подібних проблем перерахування всіх об'єктів певного типу.
Було висловлено припущення, що, можливо, ОП означає, що всі пари знаходяться на вході, а не просто їхній набір, як йдеться в запитанні. У такому випадку алгоритм набагато простіше, тому що більше не потрібно перевіряти, які пари дозволені. Не потрібно навіть генерувати набір усіх пар; наступний псевдокод зробить те, про що попросив ОП. Тут - номер введення, "список" починається як порожній список, а "накритий" - це масив довжини ініціалізований до 0. Це може бути дещо ефективніше, але це не моя найближча мета.nnn
sub cover {
i = 0;
while ( (i < n) && (covered[i] == 1 )) {
i++;
}
if ( i == n ) { print list; return;}
covered[i] = 1;
for ( j = 0; j < n; j++ ) {
if ( covered[j] == 0 ) {
covered[j] = 1;
push list, [i,j];
cover();
pop list;
covered[j] = 0;
}
}
covered[i] = 0;
}