Міністерство освіти Республіки Білорусь 
  Установа освіти 
  В«Гомельський державний університет ім. Ф. Скорини В»
  Математичний факультет 
  Кафедра МПМ 
         Реферат 
   Динамічне програмування, алгоритми на графах  
   Виконавець: 
  Студентка Старовойтова А.Ю. 
  Науковий керівник: 
  Канд. фіз-мат. наук, доцент Лебедєва М.Т. 
           Гомель 2007 
  
   Зміст 
   Введення 
  1. Алгоритми, використовують рішення додаткових підзадач 
  2. Основні визначення теорії графів 
  3. Пошук шляху між парою вершин незваженого графа 
  4. Шляхи мінімальної довжини у зваженому графі 
  Висновок 
  Література 
  
 
Введення
 
 Існує цілий клас задач з програмування, які простіше вирішуються, якщо учень володіє певним набором знань, умінь і навичок у сфері алгоритмів на графах. Це відбувається тому, що такі завдання можуть бути переформуліровани в термінах теорії графів. 
  Теорія графів містить величезну кількість визначень, теорем і алгоритмів. І тому даний матеріал не може претендувати, і не претендує, на повноту охоплення матеріалу. Однак, на думку автора, пропоновані відомості є хорошим компромісом між обсягом матеріалу і його "коефіцієнтом корисної дії" в практичному програмуванні та вирішенні олімпіадних завдань. p> Іноді вирішення основного завдання доводиться формулювати в термінах кілька модифікованих підзадач. Саме такі проблеми розглядаються в даній роботі. b> 
 
1. Алгоритми, використовують рішення додаткових підзадач
 
 Задача 9 . Потрібно підрахувати кількість різних розбиттів числа N на натуральні доданки. Два розкладання вважаються різними, якщо одне не можна отримати з іншого шляхом перестановки доданків. 
 В   
 Рішення. Для того щоб підрахувати кількість різних розбиттів числа N на довільні натуральні доданки, попередньо підрахуємо кількості разбиений на наступні групи доданків: 1) розбиття тільки на одиниці (Очевидно, що для будь-якого числа таке розбиття єдино), 2) розбиття на одиниці і двійки такі, що хоча б одна двійка в розбитті присутній і т.д. Останню групу представляє саме число N . Очевидно, що кожне розбиття числа N можна приписати тільки до однієї з розглянутих груп, залежно від значення j - максимального доданка в тому чи іншому розбитті. Позначимо кількість розбиттів в кожній з груп t ( N , j ). Тоді шукану кількість розбиттів дорівнює сумі разбиений по всіх можливих групам. Введення таких підзадач призводить до нескладного способу підрахунку числа розбиття. А саме, так як в будь-якому з разбиений j -ої групи присутній число j , то ми можемо вирахувати з N число j і скласти розбиття вже числа N - j на доданки, що не перевищують j . Тобто ми прийшли до наступного рекурентному співвідношенню: 
				
				
				
				
			  Тепер очевидно, що якщо ми маємо можливість завести двовимірний масив розміром N ' N , і будемо заповнювати його в порядку зростання номерів рядків, то завдання буде легко вирішена. Однак легко помітити, що рішення частини підзадач ніяк не беруть участь у формуванні рішення. Наприклад, при обчисленні кількості розбиттів числа 10 на доданки будуть отримані, але не використані значення t (9, j ) для j = 2 .. 9 і т. д. Для того щоб не виробляти зайвих обчислень, застосуємо динамічне програмування "зверху вниз" (усі попередні завдання вирішувалися "знизу вгору"). Для цього завдання будемо вирішувати все ж рекурсивно, використовуючи формулу (*), але відповіді до вже вирішеним підзадач будемо запам'ятовувати в таблиці. Спочатку таблиця порожня (вірніше заповнимо елементи, значення яких за формулою (*) дорівнює 0 або 1, а інші значення, наприклад, числом -1). Коли в процесі обчислень підзадача зустрічається перший раз, її рішення заноситься в таблицю. У Надалі рішення цієї підзадачі береться з таблиці. Таким чином ми отримали прийом поліпшення рекурсивних алгоритмів, а "зайві" підзадачі тепер вирішуватися не будуть. 
  Наведемо програму для вирішення цього завдання. 
   var i, j, k, n: byte; 
  sum: longint; 
  table: array [1 .. 120,1 .. 120] of longint; 
  function t (n, k: byte): longint; 
  var i, s: byte; 
  begin 
  if table [n, k] <0 then 
  {інші елементи не перераховуємо} 
  begin 
  table [n, k]: = 0; 
  for i: = 1 to k do 
  inc (table [n, k], t (n-k, i)) 
  end; 
  t: = table [n, k] 
  end; 
  begin 
  read (n); 
  fillchar (table, sizeof (table), 0); 
  for i: = 1 to n do 
  begin 
  table [i, i]: = 1; 
 <...