Зрештою, вам знадобиться математичний доказ правильності. Я перейду до деяких методів доказування для цього нижче, але спочатку, перш ніж зануритися в це, дозвольте мені заощадити трохи часу: перш ніж шукати доказ, спробуйте випадкове тестування.
Випадкове тестування
В якості першого кроку я рекомендую скористатися випадковим тестуванням для тестування алгоритму. Дивно, наскільки це ефективно: на мій досвід, для жадібних алгоритмів випадкове тестування здається нерозумно ефективним. Витратьте 5 хвилин, кодуючи свій алгоритм, і ви можете заощадити годину чи дві, намагаючись знайти доказ.
Основна ідея проста: реалізуйте свій алгоритм. Також застосуйте довідковий алгоритм, який ви знаєте правильним (наприклад, той, який вичерпно намагається використати всі можливості та скористається найкращим). Це добре, якщо ваш довідковий алгоритм асимптотично неефективний, оскільки ви запускаєте це лише в невеликих проблемних випадках. Потім генеруйте випадковим чином мільйон невеликих проблемних екземплярів, запустіть обидва алгоритми на кожному та перевірте, чи алгоритм вашого кандидата дає правильну відповідь у кожному випадку.
Якщо емпіричний алгоритм вашого кандидата є неправильним, зазвичай ви часто виявляєте це під час випадкового тестування. Якщо це здається правильним у всіх тестових випадках, то слід перейти до наступного кроку: придумати математичний доказ коректності.
Математичні докази правильності
Гаразд, тому нам потрібно довести, що наш жадібний алгоритм правильний: він виводить оптимальне рішення (або, якщо є кілька оптимальних рішень, які однаково хороші, що він виводить одне з них).
Основний принцип - інтуїтивний:
Принцип: Якщо ви ніколи не зробите поганий вибір, ви зробите все гаразд.
Жадібні алгоритми зазвичай передбачають послідовність вибору. Основна стратегія доказування полягає в тому, що ми намагаємося довести, що алгоритм ніколи не робить поганого вибору. Жадібні алгоритми не можуть відмовитися - як тільки вони роблять вибір, вони віддані і ніколи не скасовують цей вибір - тому важливо, що вони ніколи не роблять поганого вибору.
Що б вважати вдалим вибором? Якщо є єдине оптимальне рішення, легко зрозуміти, що є хорошим вибором: будь-який вибір, ідентичний вибору, зробленому оптимальним рішенням. Іншими словами, ми спробуємо довести, що на будь-якому етапі виконання жадібних алгоритмів послідовність виборів, зроблених алгоритмом, поки що точно відповідає деякому префіксу оптимального рішення. Якщо є кілька однаково хороших оптимальних рішень, хорошим вибором є той, який відповідає хоча б одному з оптимумів. Іншими словами, якщо послідовність вибору алгоритму поки що відповідає префіксу одного з оптимальних рішень, поки що все нормально (ще нічого не пішло не так).
Щоб спростити життя та усунути відволікання, зупинимось на тому випадку, коли немає зв’язків: є єдине, унікальне оптимальне рішення. Вся техніка перенесеться на той випадок, коли може бути кілька однаково хороших оптимів без будь-яких кардинальних змін, але ви повинні бути трохи уважнішими щодо технічних деталей. Почніть з ігнорування цих деталей та зосередження уваги на тому випадку, коли оптимальне рішення унікальне; це допоможе вам зосередитись на тому, що є важливим.
Існує дуже поширена модель підтвердження, яку ми використовуємо. Ми будемо наполегливо працювати, щоб довести наступну властивість алгоритму:
Твердження: Нехай - вихід рішення за алгоритмом, а O - оптимальне рішення. Якщо S відрізняється від O , то ми можемо підправити O , щоб отримати інше рішення O * , який відрізняється від O і строго краще , ніж O .SOSOOO∗OO
Зверніть увагу, чому це корисно. Якщо твердження вірно, з цього випливає, що алгоритм правильний. Це в основному доказ протиріччя. Або є таким самим, як O, або він різний. Якщо це інше, то ми можемо знайти інше рішення O ∗, що суворо краще, ніж O - але це суперечність, оскільки ми визначили, що O є оптимальним рішенням, і не може бути жодного рішення, яке краще, ніж це. Тому ми змушені зробити висновок, що S не може відрізнятися від O ; S завжди повинен дорівнювати OSОО∗ООSОSОтобто алчний алгоритм завжди виводить правильне рішення. Якщо ми можемо довести твердження вище, то ми довели, що наш алгоритм правильний.
Чудово. Тож як ми доводимо претензію? Ми розглядаємо рішення як вектор ( S 1 , ... , S n ), який відповідає послідовності n виборів, зроблених алгоритмом, і аналогічно ми вважаємо оптимальним рішення O як вектор ( O 1 , ... , про п ) , відповідний послідовності варіантів , які привели б до O . Якщо S відрізняється від O , повинен існувати деякий індекс i, де S i ≠S( S1, … , Sн)нО( О1, … , Он)ОSОi ; ми зосередимось на найменших таких я . Тоді ми налаштуємо O ,трохизмінивши O в i- му положенні, щоб відповідати S i , тобто, ми налаштуємо оптимальне рішення O , змінивши i- й вибір на той, який вибрали жадібний алгоритм, а потім ми покажемо, що це призводить до ще кращого рішення. Зокрема, ми визначимо O * бути щощось на зразокSi≠ ОiiООiSiОiО∗
O∗=(O1,O2,…,Oi−1,Si,Oi+1,Oi+2,…,On),
за винятком того, що часто нам доведеться трохи змінювати частину щоб підтримувати глобальну послідовність. Частина стратегії доказування передбачає певну розумність у належному визначенні O ∗ . Тоді м'ясо доведення буде якось використовувати факти про алгоритм і проблему, щоб показати, що O ∗ суворо краще, ніж OOi+1,Oi+2,…,OnO∗O∗O; саме тут вам знадобляться конкретні проблеми. У якийсь момент вам потрібно буде зануритися в деталі вашої конкретної проблеми. Але це дає відчуття структури типового доказу правильності алчного алгоритму.
Простий приклад: Підмножина з максимальною сумою
Це може бути простіше зрозуміти, детально розробивши простий приклад. Розглянемо наступну проблему:
Вхід: набір цілих чисел, ціле число k Вихід: Набір S ⊆ U розміром k , сума якого максимально більшаUk
S⊆Uk
Для цієї проблеми існує природний жадібний алгоритм:
- Встановити .S:=∅
- Для :
i:=1,2,…,k
- Нехай - найбільше число в U, яке ще не було вибране (тобто i- е найбільше число в U ). Додати е I в S .xiUiUxiS
Випадкове тестування передбачає, що це завжди дає оптимальне рішення, тому давайте офіційно доведемо, що цей алгоритм є правильним. Зауважте, що оптимальне рішення унікальне, тому нам не доведеться турбуватися про зв’язки. Доведемо викладене вище твердження:
Твердження: Нехай - рішення, що виводиться за цим алгоритмом на вході U , k і O - оптимальне рішення. Якщо S ≠ O , то ми можемо побудувати інше рішення O * , сума навіть більше , ніж O .SU,kOS≠OO∗O
Доказ. Припустимо , , і нехай я бути індексом першої ітерації , де х я ∉ виведення . (Такий індекс i повинен існувати, оскільки ми припустили, що S ≠ O і за визначенням алгоритму маємо S = { x 1 , … , x k } .) Оскільки (за припущенням) i мінімально, ми повинні мати x 1 , … , x i - 1 ∈ O , і зокрема,S≠Oixi∉OiS≠OS={x1,…,xk}ix1,…,xi−1∈O має вигляд O = { x 1 , x 2 , … , x i - 1 , x ′ i , x ′ i + 1 , … , x ′ n } , де числа x 1 , … , x i - 1 , x ′ i , … , x ′ nOO={x1,x2,…,xi−1,x′i,x′i+1,…,x′n}x1,…,xi−1,x′i,…,x′nперераховані у порядку зменшення. Дивлячись на те, як алгоритм вибирає , ми бачимо, що для всіх j ≥ i ми повинні мати x i > x ′ j . Зокрема, x i > x ′ i . Отже, визначимо O = O ∪ { x i } ∖ { x ′ i } , тобто отримаємо O ∗ шляхом видалення i- го числа в Ox1,…,xixi>x′jj≥ixi>x′iO=O∪{xi}∖{x′i}O∗iOі додавання . Тепер сума елементів O * є сумою елементів O плюс х I - х ' я , і х I - х ' я > 0 , так що O * «сума s строго більше , ніж O » сума s. Це доводить претензію. ◼xiO∗Oxi−x′ixi−x′i>0O∗O■
Інтуїція тут полягає в тому, що якщо жадібний алгоритм коли-небудь робить вибір, несумісний з , то ми можемо довести, що O може бути ще кращим, якби він був модифікований, щоб включати елемент, вибраний жадібним алгоритмом на цьому етапі. Оскільки О є оптимальним, не може бути жодного способу зробити його ще кращим (це було б суперечливістю), тому єдиною залишається можливістю, щоб наше припущення було невірним: іншими словами, жадібний алгоритм ніколи не зробить вибір що не узгоджується з O .OOOO
Цей аргумент часто називають обмінним аргументом або обмінною лемою . Ми знайшли перше місце, де оптимальне рішення відрізняється від жадібного рішення, і ми уявили собі обмін цього елемента на відповідний жадібний вибір (обміняли х ' i на х i ). Деякий аналіз показав, що цей обмін може лише покращити оптимальне рішення - але, за визначенням, оптимальне рішення не можна покращити. Тож єдиний висновок полягає в тому, що не повинно бути місця, де оптимальне рішення відрізняється від жадібного рішення. Якщо у вас є інша проблема, шукайте можливості застосувати цей принцип обміну у вашій конкретній ситуації.Ox′ixi