а лише один із них, найкращий у деякому розумінні, визначеному в задачі. Отже, тут з'являється таке поняття, як цінність варіантів. Загальним принципом розв'язання таких задач є скорочення обходу дерева варіантів. У ньому відкидаються деякі гілки, про які можна стверджувати, що вони не містять варіантів більш цінних, ніж уже знайдені. Розглянемо приклад.
Задача про три процесори. Нехай є три процесори, здатні виконувати завдання з однаковою швидкістю. Є набір завдань, про кожне з яких відомий час його виконання. Порядок виконання завдань неважливий. Якщо процесор почав виконувати завдання, то виконує його до кінця протягом зазначеного часу. Переключення процесора на виконання нового завдання відбувається миттєво. Треба так розподілити завдання між процесорами, шоб момент закінчення останнього завдання був мінімальним. Назвемо цю величину вартістю розподілу. Отже, займемося обчисленням мінімальної вартості серед можливих розподілів. Сам розподіл, що забезпечує таку вартість, для початку нас не цікавитиме.
Приклад. Нехай є 6 завдань, час виконання яких відповідно 7, 8, 9, 10, 11, 12. Якщо в зазначеному порядку розподілити перші три завдання між процесорами, а потім давати їх у тому ж порядку процесорам, що звільняються, то перший процесор закінчить роботу в момент 7+10=17, другий – у момент 8+11=19, а третій – 9+12=21. Маємо вартість 21. Проте їх можна розподілити інакше – 7+12, 8+11, 9+10, одержавши вартість 19.?
Перше, що ми зробимо в розв'язанні задачі – упорядкуємо завдання за незростанням часу їх виконання. Отже, нехай P1, … , Pn – завдання, часи виконання T1, … , Tn яких задовольняють нерівності T1 ? … ? Tn. Розподіл можна подати послідовністю пар вигляду (i; k), де i – номер завдання, k – номер процесора, на якому воно виконується. Наприклад, за часів 12, 11, 10, 9, 8, 7 найкращий розподіл подається як
<(1; 1), (2; 2), (3; 3), (4; 3), (5; 2), (6; 1)>.
Подібно до розміщень ферзів, можна говорити про повний розподіл – довжини n, та неповний – меншої довжини. Так само утворимо дерево пошуку розподілів. Його коренем є порожній розподіл, синами кореня – три розподіли <(1; 1)>, <(1; 2)>, <(1; 3)> тощо, тобто синами кожного розподілу вигляду
v=<(1; k1), … , (i; ki)>
за i<n є три розподіли
v1=<(1; k1), … , (i; ki), (i+1; 1)>,
v2=<(1; k1), … , (i; ki), (i+1; 2)>,
v3=<(1; k1), … , (i; ki), (i+1; 3)>.
Повні розподіли є листками вигляду <(1; k1), … , (n; kn)>.
Тепер займемося упорядкуванням обходу дерева таким чином, щоб варіанти з меншою вартістю оброблялися якомога раніше, а варіанти з більшою вартістю – якомога пізніше. За розподілом v=<(1; k1), … , (i; ki)>, де i? n, неважко обчислити трійку часів роботи процесорів (S1, S2, S3) з його виконання. Очевидно, його вартістю є найбільше з S1, S2, S3. Такий розподіл за i<n та час Ti+1 дають три варіанти трійок, відповідних його розподілам-синам v1, v2, v3:
(S1+Ti+1, S2, S3), (S1, S2+Ti+1, S3), (S1, S2, S3+Ti+1).
За i+1=n неважко вибрати найменшу з цих трьох вартостей. Проте за i+1<n нас будуть цікавити не стільки вартості цих неповних розподілів, скільки нижні оцінки вартості тих повних розподілів, які з них можна одержати. Цією оцінкою є вартість, менше якої не може бути вартість повних розподілів.
Розглянемо найпростіший спосіб такого оцінювання. Очевидно, що за неповного розподілу v перших i завдань із трійкою часів (S1, S2, S3) всі розподіли, що є його нащадками, мають вартість не меншу, ніж
E(v)=max{S1, S2, S3, min{S1, S2, S3}+Ti+1}.
Отже, оцінка E(v) є нижньою межею для вартості нащадків розподілу v.
Організуємо обхід дерева розподілів таким чином, що:
для кожного з вузлів обчислюється зазначена оцінка вартості,
вузли розглядаються у порядку зростання їх оцінок,
вузли з оцінкою, більшою від вартості вже одержаного повного розподілу, взагалі не розглядаються.
Ці міркування складають суть методу розгалужень і меж. Упорядкування вузлів робить обхід цілеспрямованим, а відкидання явно неперспективних піддерев скорочує його.
Уточнимо організацію даних для обробки вузлів у зазначеному порядку. Оскільки нас цікавлять не самі розподіли, а лише їх вартість, у вузлах дерева будемо зберігати тільки трійку часів та номер завдання, розподіленого останнім. Маючи список часів T[1], … , T[n] обробки завдань, неважко за цими даними обчислити оцінку вартості для неповних розподілів та саму вартість для повних. Для наочності цю величину також зберігатимемо у вузлі. Отже, вузол дерева подається трійкою часів S[1], S[2], S[3], номером завдання i та оцінкою вартості E, яка за i<n обчислюється як
max{ S[1], S[2], S[3], min{ S[1], S[2], S[3]}+T[i+1]}.
Очевидно, що за i=n-1 ця величина є вартістю повного розподілу, який подається "кращим із синів" цього вузла дерева.
Проміжні вузли записуються не в магазин, а в чергу, елементи якої упорядковано за зростанням оцінок вартості. Таким чином, для подання черги зручно скористатися лінійним списком (п.16.3.3). Вузли, відповідні повним розподілам, в чергу не записуються, оскільки оцінка вартості є власне їх вартістю.
Очевидно, що спочатку з трьох розподілів <(1;1)>, <(1;2)>, <(1;3)> в чергу достатньо записати лише один, для визначеності <(1; 1)>. Очевидно також, що коли обробляється вузол із однаковими часами S[1], S[2], S[3], то з трьох його синів до черги достатньо додати лише одного. Якщо ж два з трьох часів у вузлі рівні, то до черги не додається один із двох синів, що відрізняються лише порядком часів.
Опишемо обробку вузлів дерева таким алгоритмом.
Занести до черги розподіл (T[1], 0, 0;