<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nafanya</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nafanya"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Nafanya"/>
		<updated>2026-08-03T23:05:42Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D0%BC%D1%8B%D0%B5_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B8&amp;diff=51477</id>
		<title>Перечислимые языки</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%B5%D1%80%D0%B5%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D0%BC%D1%8B%D0%B5_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B8&amp;diff=51477"/>
				<updated>2016-01-19T00:58:48Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Основные определения ==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Полуразрешимый язык''' (англ. ''semi-decidable language'') {{---}} язык, для которого существует программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; такая, что&lt;br /&gt;
* &amp;lt;tex&amp;gt;\forall x \in L \Leftrightarrow p(x)=1&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\forall x \notin L \Leftrightarrow p(x)=0&amp;lt;/tex&amp;gt; или зависнет.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Перечислимый язык''' (англ. ''recursively enumerable language'') {{---}} язык, для которого существует программа &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;g(i) = x_i, L = \{x_1, x_2, .., x_n, ..\}&amp;lt;/tex&amp;gt;. Язык &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; называется '''коперечислимым''' (англ. ''co-enumerable''), если &amp;lt;tex&amp;gt;\overline L&amp;lt;/tex&amp;gt; {{---}} перечислимый. Класс всех перечислимых языков называется &amp;lt;tex&amp;gt; \mathrm{RE} &amp;lt;/tex&amp;gt;, а всех коперечислимих &amp;lt;tex&amp;gt; \mathrm{co}&amp;lt;/tex&amp;gt;-&amp;lt;tex&amp;gt;\mathrm{RE}&amp;lt;/tex&amp;gt; .&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть имеется некоторая программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, которая может либо завершиться за конечное время и что-то вернуть, либо зависнуть. Запуск программы &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; с '''тайм-лимитом''' (англ. ''time limit'') &amp;lt;tex&amp;gt;TL&amp;lt;/tex&amp;gt; будем обозначать как &amp;lt;tex&amp;gt;p|_{TL}&amp;lt;/tex&amp;gt; и иметь в виду следующее: если за &amp;lt;tex&amp;gt;TL&amp;lt;/tex&amp;gt; операций программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; корректно завершилась и что-то вернула, то &amp;lt;tex&amp;gt;p|_{TL}&amp;lt;/tex&amp;gt; вернёт то же самое; если же за &amp;lt;tex&amp;gt;TL&amp;lt;/tex&amp;gt; операций программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не успела завершиться, то &amp;lt;tex&amp;gt;p|_{TL}&amp;lt;/tex&amp;gt; вернёт &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; (символ зависания).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|id=th1&lt;br /&gt;
|statement=&lt;br /&gt;
&amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; {{---}} перечислимый &amp;lt;tex&amp;gt;\Leftrightarrow L&amp;lt;/tex&amp;gt; {{---}} полуразрешимый.&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt; \Longrightarrow &amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; {{---}} перечислимый язык. Тогда для него существует программа &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;, которая по номеру &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; выводит слово из &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;. Значит, для  всех &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; путем перебора значений функции &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; мы можем найти такое &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt; g(i) = x&amp;lt;/tex&amp;gt;. Следовательно, существует программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, такая, что &amp;lt;tex&amp;gt;\forall x: x \in L \Leftrightarrow p(x)=1&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; является полуразрешимым языком.&lt;br /&gt;
 &amp;lt;tex&amp;gt;{\bf p}&amp;lt;/tex&amp;gt;(x):&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt; i = 1 ~ .. ~ \infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt; g(i) == &amp;lt;/tex&amp;gt;x&lt;br /&gt;
       '''return''' &amp;lt;tex&amp;gt; 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; \Longleftarrow &amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; {{---}} полуразрешимый язык. Тогда для него существует программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, результат которой равен &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; для любого слова из &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;. Чтобы программа &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; не зависала на словах, которые не принадлежат &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;, будем запускать ее с тайм-лимитом. Для поиска &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-го слова из языка &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; будем перебирать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} тайм-лимит с которым будем запускать программу &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Таким образом существует программа &amp;lt;tex&amp;gt;g_0&amp;lt;/tex&amp;gt;, которая выводит &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; слово языка &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; с повторениями. Для того, чтобы выводить слова без повторений, заведем множество &amp;lt;tex&amp;gt;U&amp;lt;/tex&amp;gt;, в котором будем хранить уже выведенные слова. Программа &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; доказывает, что &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; является перечислимым языком.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;tex&amp;gt;{\bf g_0}&amp;lt;/tex&amp;gt;(i):&lt;br /&gt;
   &amp;lt;tex&amp;gt;cnt = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt; k = 1 ~ .. ~ \infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt; x \in \{x_1, x_2, .., x_k\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt; p|_k(x) == 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;cnt&amp;lt;/tex&amp;gt;++&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt; cnt == i&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''return''' &amp;lt;tex&amp;gt; x&amp;lt;/tex&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;tex&amp;gt;{\bf g}&amp;lt;/tex&amp;gt;(i):&lt;br /&gt;
   &amp;lt;tex&amp;gt;U = \emptyset&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt; j = 1 ~ .. ~ \infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;x = {\bf g_0}(j)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt; x \notin U&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;cnt&amp;lt;/tex&amp;gt;++&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt; cnt == i&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''return''' &amp;lt;tex&amp;gt; x&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;U.insert(x)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|id=th2&lt;br /&gt;
|statement=&lt;br /&gt;
Любой [[Разрешимые_(рекурсивные)_языки | разрешимый язык]] &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; является перечислимым.&lt;br /&gt;
|proof= &lt;br /&gt;
Любой разрешимый язык &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; является полуразрешимым. Так как любой полуразрешимый язык является перечислимым, то &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; является перечислимым.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
&amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; {{---}} перечислим и коперечислим &amp;lt;tex&amp;gt;\Rightarrow&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; {{---}} [[Разрешимые_(рекурсивные)_языки|разрешим]].&lt;br /&gt;
|proof=&lt;br /&gt;
Рассмотрим полуразрешители для &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\overline L&amp;lt;/tex&amp;gt; и одновременно запустим их для одного и того же элемента &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; принадлежит либо &amp;lt;tex&amp;gt; L &amp;lt;/tex&amp;gt;, либо &amp;lt;tex&amp;gt;\overline{L}&amp;lt;/tex&amp;gt;, поэтому один из полуразрешителей успешно отработает и не зависнет. Значит, мы за конечное время узнаем, лежит ли &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; или нет. Таким образом, мы построили разрешитель для &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;  {{---}} разрешимый.&lt;br /&gt;
}}&lt;br /&gt;
== Примеры перечислимых языков ==&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=st1&lt;br /&gt;
|statement=&lt;br /&gt;
Язык натуральных чисел перечислим.&lt;br /&gt;
|proof=&lt;br /&gt;
Приведём программу, перечисляющую язык натуральных чисел:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;tex&amp;gt;p(i) {:} &amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' i&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=st2&lt;br /&gt;
|statement=&lt;br /&gt;
Язык чётных неотрицательных чисел перечислим.&lt;br /&gt;
|proof=&lt;br /&gt;
Приведём программу, перечисляющую язык чётных неотрицательных чисел:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;tex&amp;gt;p(i) {:} &amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' i * 2&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры коперечислимых языков ==&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=st2&lt;br /&gt;
|statement=&lt;br /&gt;
Язык нечётных неотрицательных чисел коперечислим.&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;\overline L&amp;lt;/tex&amp;gt; - язык чётных неотрицательных чисел. Так как язык чётных неотрицательных чисел перечислим, то и язык нечётных неотрицательных чисел тоже перечислим.&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры неперечислимых языков ==&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=st2&lt;br /&gt;
|statement=&lt;br /&gt;
Язык пар &amp;lt;tex&amp;gt;\langle n, bb(n)\rangle&amp;lt;/tex&amp;gt; неперечислим.&lt;br /&gt;
|proof=&lt;br /&gt;
Функция [[Busy_beaver | busy beaver]] &amp;lt;tex&amp;gt;bb(n)&amp;lt;/tex&amp;gt; {{---}} невычислима, следовательно такой язык неперечислим.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* Н. К. Верещагин,  А. Шень. Лекции по математической логике и теории алгоритмов. Часть 3. Вычислимые функции. {{---}} М.: МЦНМО, 1999. С. 134. ISBN 5-900916-36-7&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Recursively_enumerable_language Wikipedia {{---}} Recursively enumerable language]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D0%B2%D0%BD%D0%BE_%D0%BF%D0%B5%D1%80%D0%B5%D1%87%D0%B8%D1%81%D0%BB%D0%B8%D0%BC%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA Википедия {{---}} Рекурсивно перечислимый язык]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Теория формальных языков]]&lt;br /&gt;
[[Категория: Теория вычислимости]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51329</id>
		<title>Файл:Mt3.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51329"/>
				<updated>2016-01-18T02:13:38Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: загружена новая версия «Файл:Mt3.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B0%D1%88%D0%B8%D0%BD%D0%B0_%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3%D0%B0&amp;diff=51328</id>
		<title>Машина Тьюринга</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B0%D1%88%D0%B8%D0%BD%D0%B0_%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3%D0%B0&amp;diff=51328"/>
				<updated>2016-01-18T02:08:14Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Машина Тьюринга''' (англ. ''Turing machine'') — модель абстрактного вычислителя, предложенная британским математиком Аланом Тьюрингом в 1936 году. Эта модель позволила Тьюрингу доказать два утверждения. Первое — проблема останова неразрешима, т.е. не существует такой машины Тьюринга, которая способна определить, что другая произвольная машина Тьюринга на её ленте зациклится или прекратит работу. Второе — не существует такой машины Тьюринга, которая способна определить, что другая произвольная машина Тьюринга на её ленте когда-нибудь напечатает заданный символ. В этом же году был высказан тезис Чёрча-Тьюринга, который терминах теории рекурсии формулируется как точное описание интуитивного понятия вычислимости классом общерекурсивных функций. В этой формулировке часто упоминается как просто тезис Чёрча. В терминах вычислимости по Тьюрингу тезис гласит, что для любой алгоритмически вычислимой функции существует вычисляющая её значения машина Тьюринга. В виду того, что классы частично вычислимых по Тьюрингу и частично рекурсивных функций совпадают, утверждение объединяют в единый тезис Чёрча — Тьюринга.&lt;br /&gt;
&lt;br /&gt;
Неформально машина Тьюринга определяется как устройство, состоящее из двух частей:&lt;br /&gt;
* бесконечной одномерной ленты, разделённой на ячейки,&lt;br /&gt;
* головки, которая представляет собой [[Детерминированные конечные автоматы|детерминированный конечный автомат]].&lt;br /&gt;
&lt;br /&gt;
При запуске машины Тьюринга на ленте написано входное слово, причём на первом символе этого слова находится головка, а слева и справа от него записаны пустые символы. Каждый шаг головка может перезаписать символ под лентой и сместиться на одну ячейку, если автомат приходит в допускающее или отвергающее состояние, то работа машины Тьюринга завершается.&lt;br /&gt;
&lt;br /&gt;
== Определение ==&lt;br /&gt;
=== Определение машины ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Формально '''машина Тьюринга''' (англ. ''Turing machine'') определяется как кортеж из восьми элементов &amp;lt;tex&amp;gt;\langle \Sigma, \Pi, B, Q, Y, N, S, \delta \rangle&amp;lt;/tex&amp;gt;, где&lt;br /&gt;
* &amp;lt;tex&amp;gt;\Sigma&amp;lt;/tex&amp;gt; — алфавит, из букв которого могут состоять входные слова,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\Pi \supset \Sigma&amp;lt;/tex&amp;gt; — символы, которые могут быть записаны на ленту в процессе работы машины,&lt;br /&gt;
* &amp;lt;tex&amp;gt;B \in \Pi \setminus \Sigma&amp;lt;/tex&amp;gt; ­— пробельный символ (от слова ''blank''),&lt;br /&gt;
* &amp;lt;tex&amp;gt;Q&amp;lt;/tex&amp;gt; — множество состояний управляющего автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;Y \in Q&amp;lt;/tex&amp;gt; — допускающее состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;N \in Q&amp;lt;/tex&amp;gt; — отвергающее состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;S \in Q&amp;lt;/tex&amp;gt; — стартовое состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\delta : Q \times \Pi \to Q \times \Pi \times \{ \leftarrow, \rightarrow, \downarrow \}&amp;lt;/tex&amp;gt; — всюду определённая функция перехода автомата.&lt;br /&gt;
}}&lt;br /&gt;
Отметим, что существуют различные вариации данного выше определения (например, без отвергающего состояния или с множеством допускающих состояний), которые не влияют на вычислительные способности машины Тьюринга.&lt;br /&gt;
&lt;br /&gt;
=== Определение процесса работы ===&lt;br /&gt;
Кроме формального определения самой машины требуется также формально описать процесс её работы. В определении для простоты будем предполагать, что головка в процессе работы не записывает на ленту символ &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;. Это не ограничивает вычислительной мощности машин Тьюринга, поскольку для каждой машины можно сопоставить аналогичную ей, но не пищущую &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; на ленту.&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=conf&lt;br /&gt;
|definition=&lt;br /&gt;
Назовём '''конфигурацией''' машины Тьюринга тройку &amp;lt;tex&amp;gt;\langle w, q, v \rangle&amp;lt;/tex&amp;gt;, где&lt;br /&gt;
* &amp;lt;tex&amp;gt;q \in Q&amp;lt;/tex&amp;gt; — текущее состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;w, v \in (\Pi \setminus \{B\})^*&amp;lt;/tex&amp;gt; — строки слева и справа от головки до первого пробельного символа соответственно.&lt;br /&gt;
}}&lt;br /&gt;
В данной записи головка находится над ячейкой, на которой написана первая буква &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; (или &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;v = \varepsilon&amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
В дальнейшем используются следующие обозначения: &amp;lt;tex&amp;gt;x, y, z \in \Pi&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w, v \in \Pi^*&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Определим на конфигурациях отношение перехода &amp;lt;tex&amp;gt;\langle w_1, q_1, v_1 \rangle \vdash \langle w_2, q_2, v_2 \rangle&amp;lt;/tex&amp;gt;:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \leftarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle wz, q, xv \rangle \vdash \langle w, p, zyv \rangle&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \rightarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, xv \rangle \vdash \langle wy, p, v \rangle&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \downarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, xv \rangle \vdash \langle w, p, yv \rangle&amp;lt;/tex&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
Особо следует рассмотреть случай переходов по пробельному символу:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \leftarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle wz, q, \varepsilon \rangle \vdash \langle w, p, zy \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \rightarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, \varepsilon \rangle \vdash \langle wy, p, \varepsilon \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \downarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, \varepsilon \rangle \vdash \langle w, p, y \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Очевидно, что определённое отношение является функциональным: для каждой конфигурации &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; существует не более одной конфигурации &amp;lt;tex&amp;gt;C'&amp;lt;/tex&amp;gt;, для которой &amp;lt;tex&amp;gt;C \vdash C'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для машины Тьюринга, которая пишет символ &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; на ленту также можно дать аналогичное формальное определение. Оно будет отличаться тем, что символы в строчках конфигурации могут содержать пробелы, и для того, чтобы эти строчки имекли конечную длину, нужно аккуратно учесть наличие пробелов при записи правил перехода.&lt;br /&gt;
&lt;br /&gt;
=== Результат работы ===&lt;br /&gt;
Машину Тьюринга можно рассматривать как распознаватель слов [[Основные определения: алфавит, слово, язык, конкатенация, свободный моноид слов; операции над языками|формального языка]]. Пусть &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; — машина Тьюринга, распознаваемый ей язык определяется как &amp;lt;tex&amp;gt;\mathcal L(M) = \{ x \in \Sigma^* \mid \exists y, z \in \Pi^*: \langle \varepsilon, S, x \rangle \vdash^* \langle y, Y, z \rangle \}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Также можно рассматривать машины Тьюринга как преобразователь входных данных в выходные. Машина &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; задаёт [[Вычислимые функции|вычислимую функцию]] &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, причём &amp;lt;tex&amp;gt;f(x) = y \Leftrightarrow \exists z \in \Pi^* : \langle \varepsilon, S, x \rangle \vdash^* \langle z, Y, y \rangle&amp;lt;/tex&amp;gt;. Переход автомата в состояние &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; можно интерпретировать как аварийное завершение программы (например, при некорретном входе).&lt;br /&gt;
&lt;br /&gt;
Примеры машин-распознавателей и машин-преобразователей будут даны ниже.&lt;br /&gt;
&lt;br /&gt;
== Примеры машин Тьюринга ==&lt;br /&gt;
=== Прибавление единицы ===&lt;br /&gt;
Для начала приведём пример машины-преобразователя, которая прибавляет единицу к числу, записанному на ленте в двоичной записи от младшего бита к старшему. Алгоритм следующий:&lt;br /&gt;
* в стартовом состоянии головка идёт вправо от младшего бита к старшему, заменяя все единицы на нули,&lt;br /&gt;
* встретив нуль или пробельный символ головка записывает единицу, после чего переходит в состояние &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* в состоянии &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; головка идёт влево от старшего бита к младшему, не изменяя символы 0 и 1 на ленте,&lt;br /&gt;
* встретив в состоянии &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; пробельный символ, головка перемещается на один символ вправо и переходит в состояние &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, завершая работу.&lt;br /&gt;
&lt;br /&gt;
Формально: &amp;lt;tex&amp;gt;\Sigma = \{0, 1 \}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Pi = \{0, 1, B\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;Q = \{S, R, Y, N \}&amp;lt;/tex&amp;gt;. Таблица функции &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; приведена ниже:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 |width=&amp;quot;30&amp;quot;|&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle S, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 0, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== Проверка того, является ли слово палиндромом ===&lt;br /&gt;
В качестве примера машины-распознавателя приведём машину, распознающую палиндромы над алфавитом &amp;lt;tex&amp;gt;\{0, 1\}&amp;lt;/tex&amp;gt;. Алгоритм следующий:&lt;br /&gt;
* если строка на ленте — пустая, то перейти в допускающее состояние&lt;br /&gt;
* надо запомнить первый символ слова в состоянии автомата,&lt;br /&gt;
* стереть его,&lt;br /&gt;
* перейти в конец ленты:&lt;br /&gt;
** если оставшаяся строка на ленте — пустая, то перейти в допускающее состояние&lt;br /&gt;
** если последний символ совпадает с запомненным, стереть его, перейти в начало ленты и повторить с первого шага&lt;br /&gt;
** в случае несовпадения перейти в отвергающее состояние&lt;br /&gt;
&lt;br /&gt;
Формально: &amp;lt;tex&amp;gt;\Sigma = \{0, 1\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Pi = \{0, 1, B\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;Q = \{S, F_0, F_1, B_0, B_1, R \}&amp;lt;/tex&amp;gt;. Таблица функции &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; приведена ниже:&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 |width=&amp;quot;30&amp;quot;|&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;F_0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, 1, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle B_0, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;F_1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, 1, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle B_1, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;B_0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle N, 1, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;B_1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle N, 0, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 0, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle S, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
== Варианты машины Тьюринга ==&lt;br /&gt;
В этом разделе приведены различные варианты машин Тьюринга, которые не отличаются от обычных машин Тьюринга по вычислительной мощности.&lt;br /&gt;
&lt;br /&gt;
=== Многодорожечная машина Тьюринга ===&lt;br /&gt;
Машиной Тьюринга с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожками называется вычислитель, аналогичный машине Тьюринга, лишь с тем отличием, что лента состоит из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожек, на каждой из которых записаны символы ленточного алфавита. У многодорожечной машины одна головка, которая за один шаг переходит в одном направлении на всех дорожках одновременно. Соответственно, функция перехода имеет тип &amp;lt;tex&amp;gt;\delta : Q \times \Pi^n \to Q \times \Pi^n \times \{\leftarrow, \rightarrow, \downarrow\}&amp;lt;/tex&amp;gt;. Многодорожечная машина Тьюринга тривиально эквивалентна обычной с ленточным алфавитом &amp;lt;tex&amp;gt;\Pi' = \Pi^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Машина Тьюринга с полубесконечной лентой ===&lt;br /&gt;
Заменив у машины Тьюринга бесконечную в обе стороны ленту на бесконечную в одну сторону, мы не теряем в вычислительной мощности. По произвольной машине Тьюринга строится двухдорожечная машина с полубесконечной лентой.&lt;br /&gt;
{{Теорема&lt;br /&gt;
|author=&lt;br /&gt;
|statement=Для любой машины Тьюринга существует эквивалентная машина Тьюринга, работающая на полубесконечной ленте.&lt;br /&gt;
|proof=Существует алгоритм, по которому для любой машины Тьюринга может быть построена эквивалентная машина Тьюринга с объявленным свойством. Сначала занумеруем ячейки рабочей ленты машины Тьюринга с ''бесконечной лентой'' следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt1.png]]&lt;br /&gt;
&lt;br /&gt;
Затем перенумеруем ячейки, и запишем символ &amp;lt;tex&amp;gt;c \in \Pi \setminus \Sigma, B&amp;lt;/tex&amp;gt; в начало ленты, который будет означать границу рабочей зоны:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt2.png]]&lt;br /&gt;
&lt;br /&gt;
Наконец, изменим машину Тьюринга, удвоив число её состояний, и изменим сдвиг головки так, чтобы в одной группе состояний работа машины была бы эквивалентна её работе в заштрихованной зоне, а в другой группе состояний машина работала бы так, как исходная машина работает в незаштрихованной зоне. Если при работе машины Тьюринга встретится символ &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, значит головка достигла границы рабочей зоны:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt3.png]]&lt;br /&gt;
&lt;br /&gt;
Начальное состояние новой машины Тьюринга устанавливается в одной или другой зоне в зависимости от того, в какой части исходной ленты располагалась головка считывания-записи в исходной конфигурации.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Многоленточная машина Тьюринга ===&lt;br /&gt;
В отличие от многодорожечной машины Тьюринга, ленты не зависят друг от друга и головки во время одного шага могу перемещаться по-разному. То есть, функция перехода теперь имеет тип &amp;lt;tex&amp;gt;\delta : Q \times \Pi^n \to Q \times \Pi^n \times \{\leftarrow, \rightarrow, \downarrow\}^n&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Многоленточная машина с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожками эмулируется многодорожечной машиной с &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; дорожками следующим образом: каждая нечётная дорожка соответствует ленте исходной машины, а на каждой чётной дорожке отмечены специальным символом &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt; позиция головки на ленте выше (считаем, что ленты нумеруются сверху вниз).&lt;br /&gt;
&lt;br /&gt;
Каждый шаг исходной машины эмулируется конечной последовательностью шагов построенной машины следующим образом: исходно головка находится в позиции самой левой отметки и идёт вправо до самой правой отметки, запоминая прочитанные около символов &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt; символы в состоянии. Пройдя до самой правой отметки, головка возвращается влево, совершая необходимые действия (переписывая символы около отметок и передвигая сами отметки). После такого прохода головка переходит в следующее состояние, завершая эмуляцию шага.&lt;br /&gt;
&lt;br /&gt;
Аланом Тьюрингом было сформулировано следующее утверждение:&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|about=Тезис Чёрча-Тьюринга&lt;br /&gt;
|statement=&lt;br /&gt;
Класс перечислимых языков совпадает с классом языков, перечислимых с помощью машин Тьюринга&lt;br /&gt;
}}&lt;br /&gt;
Иными словами, тезис говорит о том, что любой алгоритм можно запрограммировать на машине Тьюринга.&lt;br /&gt;
&lt;br /&gt;
== Универсальная машина Тьюринга ==&lt;br /&gt;
&lt;br /&gt;
Существует машина Тьюринга, которая принимает на вход закодированное описание произвольной машины и входную строку и эмулирует работу закодированной машины на заданном входном слове. Иными словами, [[Разрешимые (рекурсивные) языки#Пример неразрешимого множества|универсальный язык]] перечислим с помощью машины Тьюринга. Ссылки на явные конструкции универсальных машин Тьюринга приведены ниже.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Стековые машины, эквивалентность двухстековой машины МТ|Стековые машины]]&lt;br /&gt;
* [[Счетчиковые машины, эквивалентность двухсчетчиковой машины МТ|Счётчиковые машины]]&lt;br /&gt;
* [[Линейный клеточный автомат, эквивалентность МТ|Клеточные автоматы]]&lt;br /&gt;
* [[Возможность порождения формальной грамматикой произвольного перечислимого языка|Произвольные формальные грамматики]]&lt;br /&gt;
* [[Лямбда-исчисление|Нетипизированное лямбда-исчисление]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf Alan Turing {{---}} On computable numbers, with an application to the Entscheidungsproblem.]&lt;br /&gt;
* [http://www.ccs.neu.edu/home/viola/classes/papers/HennieStearns66.pdf F. C. Hennie, R. E. Stearn {{---}} Two-tape simulation of multitape Turing machines.]&lt;br /&gt;
* [http://www.cs.princeton.edu/theory/index.php/Compbook/Draft Sanjeev Arora, Boaz Barak {{---}} Computational Complexity: A Modern Approach.]&lt;br /&gt;
* [http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.8958 Turlough Neary, Damien Woods {{---}} Four Small Universal Turing Machines.]&lt;br /&gt;
* [http://www.jflap.org/ JFLAP {{---}} ПО для изучения формальных языков, включает в себя эмулятор одноленточных и многоленточных машин Тьюринга с визуальным редактором.]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Теория формальных языков]]&lt;br /&gt;
[[Категория: Теория вычислимости]]&lt;br /&gt;
[[Категория: Вычислительные формализмы]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt1.png&amp;diff=51327</id>
		<title>Файл:Mt1.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt1.png&amp;diff=51327"/>
				<updated>2016-01-18T02:06:59Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: загружена новая версия «Файл:Mt1.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt2.png&amp;diff=51326</id>
		<title>Файл:Mt2.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt2.png&amp;diff=51326"/>
				<updated>2016-01-18T02:06:37Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: загружена новая версия «Файл:Mt2.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51325</id>
		<title>Файл:Mt3.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51325"/>
				<updated>2016-01-17T21:35:30Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: загружена новая версия «Файл:Mt3.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51324</id>
		<title>Файл:Mt3.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51324"/>
				<updated>2016-01-17T21:35:09Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: загружена новая версия «Файл:Mt3.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51323</id>
		<title>Файл:Mt3.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.png&amp;diff=51323"/>
				<updated>2016-01-17T21:09:01Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B0%D1%88%D0%B8%D0%BD%D0%B0_%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3%D0%B0&amp;diff=51156</id>
		<title>Машина Тьюринга</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B0%D1%88%D0%B8%D0%BD%D0%B0_%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3%D0%B0&amp;diff=51156"/>
				<updated>2016-01-14T14:19:29Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Машина Тьюринга''' (англ. ''Turing machine'') — модель абстрактного вычислителя, предложенная британским математиком Аланом Тьюрингом в 1936 году. Эта модель позволила Тьюрингу доказать два утверждения. Первое — проблема останова неразрешима, т.е. не существует такой машины Тьюринга, которая способна определить, что другая произвольная машина Тьюринга на её ленте зациклится или прекратит работу. Второе — не существует такой машины Тьюринга, которая способна определить, что другая произвольная машина Тьюринга на её ленте когда-нибудь напечатает заданный символ. В этом же году был высказан тезис Чёрча-Тьюринга, который терминах теории рекурсии формулируется как точное описание интуитивного понятия вычислимости классом общерекурсивных функций. В этой формулировке часто упоминается как просто тезис Чёрча. В терминах вычислимости по Тьюрингу тезис гласит, что для любой алгоритмически вычислимой функции существует вычисляющая её значения машина Тьюринга. В виду того, что классы частично вычислимых по Тьюрингу и частично рекурсивных функций совпадают, утверждение объединяют в единый тезис Чёрча — Тьюринга.&lt;br /&gt;
&lt;br /&gt;
Неформально машина Тьюринга определяется как устройство, состоящее из двух частей:&lt;br /&gt;
* бесконечной одномерной ленты, разделённой на ячейки,&lt;br /&gt;
* головки, которая представляет собой [[Детерминированные конечные автоматы|детерминированный конечный автомат]].&lt;br /&gt;
&lt;br /&gt;
При запуске машины Тьюринга на ленте написано входное слово, причём на первом символе этого слова находится головка, а слева и справа от него записаны пустые символы. Каждый шаг головка может перезаписать символ под лентой и сместиться на одну ячейку, если автомат приходит в допускающее или отвергающее состояние, то работа машины Тьюринга завершается.&lt;br /&gt;
&lt;br /&gt;
== Определение ==&lt;br /&gt;
=== Определение машины ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Формально '''машина Тьюринга''' (англ. ''Turing machine'') определяется как кортеж из восьми элементов &amp;lt;tex&amp;gt;\langle \Sigma, \Pi, B, Q, Y, N, S, \delta \rangle&amp;lt;/tex&amp;gt;, где&lt;br /&gt;
* &amp;lt;tex&amp;gt;\Sigma&amp;lt;/tex&amp;gt; — алфавит, из букв которого могут состоять входные слова,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\Pi \supset \Sigma&amp;lt;/tex&amp;gt; — символы, которые могут быть записаны на ленту в процессе работы машины,&lt;br /&gt;
* &amp;lt;tex&amp;gt;B \in \Pi \setminus \Sigma&amp;lt;/tex&amp;gt; ­— пробельный символ (от слова ''blank''),&lt;br /&gt;
* &amp;lt;tex&amp;gt;Q&amp;lt;/tex&amp;gt; — множество состояний управляющего автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;Y \in Q&amp;lt;/tex&amp;gt; — допускающее состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;N \in Q&amp;lt;/tex&amp;gt; — отвергающее состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;S \in Q&amp;lt;/tex&amp;gt; — стартовое состояние автомата,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\delta : Q \times \Pi \to Q \times \Pi \times \{ \leftarrow, \rightarrow, \downarrow \}&amp;lt;/tex&amp;gt; — всюду определённая функция перехода автомата&lt;br /&gt;
}}&lt;br /&gt;
Отметим, что существуют различные вариации данного выше определения (например, без отвергающего состояния или с множеством допускающих состояний), которые не влияют на вычислительные способности машины Тьюринга.&lt;br /&gt;
&lt;br /&gt;
=== Определение процесса работы ===&lt;br /&gt;
Кроме формального определения самой машины требуется также формально описать процесс её работы. В определении для простоты будем предполагать, что головка в процессе работы не записывает на ленту символ &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;. Это не ограничивает вычислительной мощности машин Тьюринга, поскольку для каждой машины можно сопоставить аналогичную ей, но не пищущую &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; на ленту.&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=conf&lt;br /&gt;
|definition=&lt;br /&gt;
Назовём '''конфигурацией''' машины Тьюринга тройку &amp;lt;tex&amp;gt;\langle w, q, v \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;q \in Q&amp;lt;/tex&amp;gt; — текущее состояние автомата, а &amp;lt;tex&amp;gt;w, v \in (\Pi \setminus \{B\})^*&amp;lt;/tex&amp;gt; — строки слева и справа от головки до первого пробельного символа соответственно.&lt;br /&gt;
}}&lt;br /&gt;
В данной записи головка находится над ячейкой, на которой написана первая буква &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; (или &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;v = \varepsilon&amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
В дальнейшем используются следующие обозначения: &amp;lt;tex&amp;gt;x, y, z \in \Pi&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w, v \in \Pi^*&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Определим на конфигурациях отношение перехода &amp;lt;tex&amp;gt;\langle w_1, q_1, v_1 \rangle \vdash \langle w_2, q_2, v_2 \rangle&amp;lt;/tex&amp;gt;:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \leftarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle wz, q, xv \rangle \vdash \langle w, p, zyv \rangle&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \rightarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, xv \rangle \vdash \langle wy, p, v \rangle&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \downarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, xv \rangle \vdash \langle w, p, yv \rangle&amp;lt;/tex&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
Особо следует рассмотреть случай переходов по пробельному символу:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \leftarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle wz, q, \varepsilon \rangle \vdash \langle w, p, zy \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \rightarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, \varepsilon \rangle \vdash \langle wy, p, \varepsilon \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \downarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, \varepsilon \rangle \vdash \langle w, p, y \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Очевидно, что определённое отношение является функциональным: для каждой конфигурации &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; существует не более одной конфигурации &amp;lt;tex&amp;gt;C'&amp;lt;/tex&amp;gt;, для которой &amp;lt;tex&amp;gt;C \vdash C'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для машины Тьюринга, которая пишет символ &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; на ленту также можно дать аналогичное формальное определение. Оно будет отличаться тем, что символы в строчках конфигурации могут содержать пробелы, и для того, чтобы эти строчки имекли конечную длину, нужно аккуратно учесть наличие пробелов при записи правил перехода.&lt;br /&gt;
&lt;br /&gt;
=== Результат работы ===&lt;br /&gt;
Машину Тьюринга можно рассматривать как распознаватель слов [[Основные определения: алфавит, слово, язык, конкатенация, свободный моноид слов; операции над языками|формального языка]]. Пусть &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; — машина Тьюринга, распознаваемый ей язык определяется как &amp;lt;tex&amp;gt;\mathcal L(M) = \{ x \in \Sigma^* \mid \exists y, z \in \Pi^*: \langle \varepsilon, S, x \rangle \vdash^* \langle y, Y, z \rangle \}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Также можно рассматривать машины Тьюринга как преобразователь входных данных в выходные. Машина &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; задаёт [[Вычислимые функции|вычислимую функцию]] &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, причём &amp;lt;tex&amp;gt;f(x) = y \Leftrightarrow \exists z \in \Pi^* : \langle \varepsilon, S, x \rangle \vdash^* \langle z, Y, y \rangle&amp;lt;/tex&amp;gt;. Переход автомата в состояние &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; можно интерпретировать как аварийное завершение программы (например, при некорретном входе).&lt;br /&gt;
&lt;br /&gt;
Примеры машин-распознавателей и машин-преобразователей будут даны ниже.&lt;br /&gt;
&lt;br /&gt;
== Примеры машин Тьюринга ==&lt;br /&gt;
=== Прибавление единицы ===&lt;br /&gt;
Для начала приведём пример машины-преобразователя, которая прибавляет единицу к числу, записанному на ленте в двоичной записи от младшего бита к старшему. Алгоритм следующий:&lt;br /&gt;
* в стартовом состоянии головка идёт вправо от младшего бита к старшему, заменяя все единицы на нули,&lt;br /&gt;
* встретив нуль или пробельный символ головка записывает единицу, после чего переходит в состояние &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* в состоянии &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; головка идёт влево от старшего бита к младшему, не изменяя символы 0 и 1 на ленте,&lt;br /&gt;
* встретив в состоянии &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; пробельный символ, головка перемещается на один символ вправо и переходит в состояние &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, завершая работу.&lt;br /&gt;
&lt;br /&gt;
Формально: &amp;lt;tex&amp;gt;\Sigma = \{0, 1 \}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Pi = \{0, 1, B\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;Q = \{S, R, Y, N \}&amp;lt;/tex&amp;gt;. Таблица функции &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; приведена ниже:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 |width=&amp;quot;30&amp;quot;|&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle S, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 0, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== Проверка того, является ли слово палиндромом ===&lt;br /&gt;
В качестве примера машины-распознавателя приведём машину, распознающую палиндромы над алфавитом &amp;lt;tex&amp;gt;\{0, 1\}&amp;lt;/tex&amp;gt;. Алгоритм следующий:&lt;br /&gt;
* если строка на ленте — пустая, то перейти в допускающее состояние&lt;br /&gt;
* надо запомнить первый символ слова в состоянии автомата,&lt;br /&gt;
* стереть его,&lt;br /&gt;
* перейти в конец ленты:&lt;br /&gt;
** если оставшаяся строка на ленте — пустая, то перейти в допускающее состояние&lt;br /&gt;
** если последний символ совпадает с запомненным, стереть его, перейти в начало ленты и повторить с первого шага&lt;br /&gt;
** в случае несовпадения перейти в отвергающее состояние&lt;br /&gt;
&lt;br /&gt;
Формально: &amp;lt;tex&amp;gt;\Sigma = \{0, 1\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Pi = \{0, 1, B\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;Q = \{S, F_0, F_1, B_0, B_1, R \}&amp;lt;/tex&amp;gt;. Таблица функции &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; приведена ниже:&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 |width=&amp;quot;30&amp;quot;|&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;F_0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, 1, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle B_0, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;F_1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, 1, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle B_1, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;B_0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle N, 1, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;B_1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle N, 0, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 0, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle S, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
== Варианты машины Тьюринга ==&lt;br /&gt;
В этом разделе приведены различные варианты машин Тьюринга, которые не отличаются от обычных машин Тьюринга по вычислительной мощности.&lt;br /&gt;
&lt;br /&gt;
=== Многодорожечная машина Тьюринга ===&lt;br /&gt;
Машиной Тьюринга с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожками называется вычислитель, аналогичный машине Тьюринга, лишь с тем отличием, что лента состоит из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожек, на каждой из которых записаны символы ленточного алфавита. У многодорожечной машины одна головка, которая за один шаг переходит в одном направлении на всех дорожках одновременно. Соответственно, функция перехода имеет тип &amp;lt;tex&amp;gt;\delta : Q \times \Pi^n \to Q \times \Pi^n \times \{\leftarrow, \rightarrow, \downarrow\}&amp;lt;/tex&amp;gt;. Многодорожечная машина Тьюринга тривиально эквивалентна обычной с ленточным алфавитом &amp;lt;tex&amp;gt;\Pi' = \Pi^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Машина Тьюринга с полубесконечной лентой ===&lt;br /&gt;
Заменив у машины Тьюринга бесконечную в обе стороны ленту на бесконечную в одну сторону, мы не теряем в вычислительной мощности. По произвольной машине Тьюринга строится двухдорожечная машина с полубесконечной лентой.&lt;br /&gt;
{{Теорема&lt;br /&gt;
|author=&lt;br /&gt;
|statement=Для любой машины Тьюринга существует эквивалентная машина Тьюринга, работающая на полубесконечной ленте.&lt;br /&gt;
|proof=Существует алгоритм, по которому для любой машины Тьюринга может быть построена эквивалентная машина Тьюринга с объявленным свойством. Сначала занумеруем ячейки рабочей ленты машины Тьюринга с ''бесконечной лентой'' следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt1.png]]&lt;br /&gt;
&lt;br /&gt;
Затем перенумеруем ячейки, и запишем символ &amp;lt;tex&amp;gt;c \in \Pi \setminus \Sigma, B&amp;lt;/tex&amp;gt; в начало ленты, который будет означать границу рабочей зоны:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt2.png]]&lt;br /&gt;
&lt;br /&gt;
Наконец, изменим машину Тьюринга, удвоив число её состояний, и изменим сдвиг головки так, чтобы в одной группе состояний работа машины была бы эквивалентна её работе в заштрихованной зоне, а в другой группе состояний машина работала бы так, как исходная машина работает в незаштрихованной зоне. Если при работе машины Тьюринга встретится символ &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, значит головка достигла границы рабочей зоны:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt3.jpg]]&lt;br /&gt;
&lt;br /&gt;
Начальное состояние новой машины Тьюринга устанавливается в одной или другой зоне в зависимости от того, в какой части исходной ленты располагалась головка считывания-записи в исходной конфигурации.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Многоленточная машина Тьюринга ===&lt;br /&gt;
В отличие от многодорожечной машины Тьюринга, ленты не зависят друг от друга и головки во время одного шага могу перемещаться по-разному. То есть, функция перехода теперь имеет тип &amp;lt;tex&amp;gt;\delta : Q \times \Pi^n \to Q \times \Pi^n \times \{\leftarrow, \rightarrow, \downarrow\}^n&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Многоленточная машина с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожками эмулируется многодорожечной машиной с &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; дорожками следующим образом: каждая нечётная дорожка соответствует ленте исходной машины, а на каждой чётной дорожке отмечены специальным символом &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt; позиция головки на ленте выше (считаем, что ленты нумеруются сверху вниз).&lt;br /&gt;
&lt;br /&gt;
Каждый шаг исходной машины эмулируется конечной последовательностью шагов построенной машины следующим образом: исходно головка находится в позиции самой левой отметки и идёт вправо до самой правой отметки, запоминая прочитанные около символов &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt; символы в состоянии. Пройдя до самой правой отметки, головка возвращается влево, совершая необходимые действия (переписывая символы около отметок и передвигая сами отметки). После такого прохода головка переходит в следующее состояние, завершая эмуляцию шага.&lt;br /&gt;
&lt;br /&gt;
Аланом Тьюрингом было сформулировано следующее утверждение:&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|about=Тезис Чёрча-Тьюринга&lt;br /&gt;
|statement=&lt;br /&gt;
Класс перечислимых языков совпадает с классом языков, перечислимых с помощью машин Тьюринга&lt;br /&gt;
}}&lt;br /&gt;
Иными словами, тезис говорит о том, что любой алгоритм можно запрограммировать на машине Тьюринга.&lt;br /&gt;
&lt;br /&gt;
== Универсальная машина Тьюринга ==&lt;br /&gt;
&lt;br /&gt;
Существует машина Тьюринга, которая принимает на вход закодированное описание произвольной машины и входную строку и эмулирует работу закодированной машины на заданном входном слове. Иными словами, [[Разрешимые (рекурсивные) языки#Пример неразрешимого множества|универсальный язык]] перечислим с помощью машины Тьюринга. Ссылки на явные конструкции универсальных машин Тьюринга приведены ниже.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Стековые машины, эквивалентность двухстековой машины МТ|стековые машины]]&lt;br /&gt;
* [[Счетчиковые машины, эквивалентность двухсчетчиковой машины МТ|счётчиковые машины]]&lt;br /&gt;
* [[Линейный клеточный автомат, эквивалентность МТ|клеточные автоматы]]&lt;br /&gt;
* [[Возможность порождения формальной грамматикой произвольного перечислимого языка|произвольные формальные грамматики]]&lt;br /&gt;
* [[Лямбда-исчисление|нетипизированное лямбда-исчисление]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf Alan Turing {{---}} On computable numbers, with an application to the Entscheidungsproblem.]&lt;br /&gt;
* [http://www.ccs.neu.edu/home/viola/classes/papers/HennieStearns66.pdf F. C. Hennie, R. E. Stearn {{---}} Two-tape simulation of multitape Turing machines.]&lt;br /&gt;
* [http://www.cs.princeton.edu/theory/index.php/Compbook/Draft Sanjeev Arora, Boaz Barak {{---}} Computational Complexity: A Modern Approach.]&lt;br /&gt;
* [http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.8958 Turlough Neary, Damien Woods {{---}} Four Small Universal Turing Machines.]&lt;br /&gt;
* [http://www.jflap.org/ JFLAP {{---}} ПО для изучения формальных языков, включает в себя эмулятор одноленточных и многоленточных машин Тьюринга с визуальным редактором.]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Теория формальных языков]]&lt;br /&gt;
[[Категория: Теория вычислимости]]&lt;br /&gt;
[[Категория: Вычислительные формализмы]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt2.png&amp;diff=51116</id>
		<title>Файл:Mt2.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt2.png&amp;diff=51116"/>
				<updated>2016-01-14T01:03:51Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt1.png&amp;diff=51008</id>
		<title>Файл:Mt1.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt1.png&amp;diff=51008"/>
				<updated>2016-01-10T19:29:17Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B0%D1%88%D0%B8%D0%BD%D0%B0_%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3%D0%B0&amp;diff=50852</id>
		<title>Машина Тьюринга</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B0%D1%88%D0%B8%D0%BD%D0%B0_%D0%A2%D1%8C%D1%8E%D1%80%D0%B8%D0%BD%D0%B3%D0%B0&amp;diff=50852"/>
				<updated>2016-01-07T18:57:34Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: тикет 3.14&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Машина Тьюринга''' (англ. ''Turing machine'') — модель абстрактного вычислителя, предложенная британским математиком Аланом Тьюрингом в 1936 году. Эта модель позволила Тьюрингу доказать два утверждения. Первое - проблема останова неразрешима, т.е. не существует такой машины Тьюринга, которая способна определить, что другая произвольная машина Тьюринга на её ленте зациклится или прекратит работу. Второе - не существует такой машины Тьюринга, которая способна определить, что другая произвольная машина Тьюринга на её ленте когда-нибудь напечатает заданный символ. В этом же году был высказан тезис Чёрча-Тьюринга, который терминах теории рекурсии формулируется как точное описание интуитивного понятия вычислимости классом общерекурсивных функций. В этой формулировке часто упоминается как просто тезис Чёрча. В терминах вычислимости по Тьюрингу тезис гласит, что для любой алгоритмически вычислимой функции существует вычисляющая её значения машина Тьюринга. В виду того, что классы частично вычислимых по Тьюрингу и частично рекурсивных функций совпадают, утверждение объединяют в единый тезис Чёрча — Тьюринга.&lt;br /&gt;
&lt;br /&gt;
Неформально машина Тьюринга определяется как устройство, состоящее из двух частей:&lt;br /&gt;
* бесконечной одномерной ленты, разделённой на ячейки,&lt;br /&gt;
* головки, которая представляет собой [[Детерминированные конечные автоматы|детерминированный конечный автомат]].&lt;br /&gt;
&lt;br /&gt;
При запуске машины Тьюринга на ленте написано входное слово, причём на первом символе этого слова находится головка, а слева и справа от него записаны пустые символы. Каждый шаг головка может перезаписать символ под лентой и сместиться на одну ячейку, если автомат приходит в допускающее или отвергающее состояние, то работа машины Тьюринга завершается.&lt;br /&gt;
&lt;br /&gt;
== Определение ==&lt;br /&gt;
=== Определение машины ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Формально '''машина Тьюринга''' определяется как кортеж из восьми элементов &amp;lt;tex&amp;gt;\langle \Sigma, \Pi, B, Q, Y, N, S, \delta \rangle&amp;lt;/tex&amp;gt;, где&lt;br /&gt;
* &amp;lt;tex&amp;gt;\Sigma&amp;lt;/tex&amp;gt; — алфавит, из букв которого могут состоять входные слова&lt;br /&gt;
* &amp;lt;tex&amp;gt;\Pi \supset \Sigma&amp;lt;/tex&amp;gt; — символы, которые могут быть записаны на ленту в процессе работы машины&lt;br /&gt;
* &amp;lt;tex&amp;gt;B \in \Pi \setminus \Sigma&amp;lt;/tex&amp;gt; ­— пробельный символ (от слова ''blank'')&lt;br /&gt;
* &amp;lt;tex&amp;gt;Q&amp;lt;/tex&amp;gt; — множество состояний управляющего автомата&lt;br /&gt;
* &amp;lt;tex&amp;gt;Y \in Q&amp;lt;/tex&amp;gt; — допускающее состояние автомата&lt;br /&gt;
* &amp;lt;tex&amp;gt;N \in Q&amp;lt;/tex&amp;gt; — отвергающее состояние автомата&lt;br /&gt;
* &amp;lt;tex&amp;gt;S \in Q&amp;lt;/tex&amp;gt; — стартовое состояние автомата&lt;br /&gt;
* &amp;lt;tex&amp;gt;\delta : Q \times \Pi \to Q \times \Pi \times \{ \leftarrow, \rightarrow, \downarrow \}&amp;lt;/tex&amp;gt; — всюду определённая функция перехода автомата&lt;br /&gt;
}}&lt;br /&gt;
Отметим, что существуют различные вариации данного выше определения (например, без отвергающего состояния или с множеством допускающих состояний), которые не влияют на вычислительные способности машины Тьюринга.&lt;br /&gt;
&lt;br /&gt;
=== Определение процесса работы ===&lt;br /&gt;
Кроме формального определения самой машины требуется также формально описать процесс её работы. В определении для простоты будем предполагать, что головка в процессе работы не записывает на ленту символ &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;. Это не ограничивает вычислительной мощности машин Тьюринга, поскольку для каждой машины можно сопоставить аналогичную ей, но не пищущую &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; на ленту.&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=conf&lt;br /&gt;
|definition=&lt;br /&gt;
Назовём '''конфигурацией''' машины Тьюринга тройку &amp;lt;tex&amp;gt;\langle w, q, v \rangle&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;q \in Q&amp;lt;/tex&amp;gt; — текущее состояние автомата, а &amp;lt;tex&amp;gt;w, v \in (\Pi \setminus \{B\})^*&amp;lt;/tex&amp;gt; — строки слева и справа от головки до первого пробельного символа соответственно.&lt;br /&gt;
}}&lt;br /&gt;
В данной записи головка находится над ячейкой, на которой написана первая буква &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; (или &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;v = \varepsilon&amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
В дальнейшем используются следующие обозначения: &amp;lt;tex&amp;gt;x, y, z \in \Pi&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;w, v \in \Pi^*&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
Определим на конфигурациях отношение перехода &amp;lt;tex&amp;gt;\langle w_1, q_1, v_1 \rangle \vdash \langle w_2, q_2, v_2 \rangle&amp;lt;/tex&amp;gt;:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \leftarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle wz, q, xv \rangle \vdash \langle w, p, zyv \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \rightarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, xv \rangle \vdash \langle wy, p, v \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, x) = \langle p, y, \downarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, xv \rangle \vdash \langle w, p, yv \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Особо следует рассмотреть случай переходов по пробельному символу:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \leftarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle wz, q, \varepsilon \rangle \vdash \langle w, p, zy \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \rightarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, \varepsilon \rangle \vdash \langle wy, p, \varepsilon \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\delta(q, B) = \langle p, y, \downarrow \rangle&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\langle w, q, \varepsilon \rangle \vdash \langle w, p, y \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Очевидно, что определённое отношение является функциональным: для каждой конфигурации &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; существует не более одной конфигурации &amp;lt;tex&amp;gt;C'&amp;lt;/tex&amp;gt;, для которой &amp;lt;tex&amp;gt;C \vdash C'&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для машины Тьюринга, которая пишет символ &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; на ленту также можно дать аналогичное формальное определение. Оно будет отличаться тем, что символы в строчках конфигурации могут содержать пробелы, и для того, чтобы эти строчки имекли конечную длину, нужно аккуратно учесть наличие пробелов при записи правил перехода.&lt;br /&gt;
&lt;br /&gt;
=== Результат работы ===&lt;br /&gt;
Машину Тьюринга можно рассматривать как распознаватель слов [[Основные определения: алфавит, слово, язык, конкатенация, свободный моноид слов; операции над языками|формального языка]]. Пусть &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; — машина Тьюринга, распознаваемый ей язык определяется как &amp;lt;tex&amp;gt;\mathcal L(M) = \{ x \in \Sigma^* \mid \exists y, z \in \Pi^*: \langle \varepsilon, S, x \rangle \vdash^* \langle y, Y, z \rangle \}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Также можно рассматривать машины Тьюринга как преобразователь входных данных в выходные. Машина &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; задаёт [[Вычислимые функции|вычислимую функцию]] &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, причём &amp;lt;tex&amp;gt;f(x) = y \Leftrightarrow \exists z \in \Pi^* : \langle \varepsilon, S, x \rangle \vdash^* \langle z, Y, y \rangle&amp;lt;/tex&amp;gt;. Переход автомата в состояние &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; можно интерпретировать как аварийное завершение программы (например, при некорретном входе).&lt;br /&gt;
&lt;br /&gt;
Примеры машин-распознавателей и машин-преобразователей будут даны ниже.&lt;br /&gt;
&lt;br /&gt;
== Примеры машин Тьюринга ==&lt;br /&gt;
=== Прибавление единицы ===&lt;br /&gt;
Для начала приведём пример машины-преобразователя, которая прибавляет единицу к числу, записанному на ленте в двоичной записи от младшего бита к старшему. Алгоритм следующий:&lt;br /&gt;
* в стартовом состоянии головка идёт вправо от младшего бита к старшему, заменяя все единицы на нули,&lt;br /&gt;
* встретив нуль или пробельный символ головка записывает единицу, после чего переходит в состояние &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* в состоянии &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; головка идёт влево от старшего бита к младшему, не изменяя символы 0 и 1 на ленте,&lt;br /&gt;
* встретив в состоянии &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt; пробельный символ, головка перемещается на один символ вправо и переходит в состояние &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, завершая работу.&lt;br /&gt;
&lt;br /&gt;
Формально: &amp;lt;tex&amp;gt;\Sigma = \{0, 1 \}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Pi = \{0, 1, B\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;Q = \{S, R, Y, N \}&amp;lt;/tex&amp;gt;. Таблица функции &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; приведена ниже:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 |width=&amp;quot;30&amp;quot;|&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle S, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 0, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
=== Проверка того, является ли слово палиндромом ===&lt;br /&gt;
В качестве примера машины-распознавателя приведём машину, распознающую палиндромы над алфавитом &amp;lt;tex&amp;gt;\{0, 1\}&amp;lt;/tex&amp;gt;. Алгоритм следующий:&lt;br /&gt;
* если строка на ленте — пустая, то перейти в допускающее состояние&lt;br /&gt;
* надо запомнить первый символ слова в состоянии автомата,&lt;br /&gt;
* стереть его,&lt;br /&gt;
* перейти в конец ленты:&lt;br /&gt;
** если оставшаяся строка на ленте — пустая, то перейти в допускающее состояние&lt;br /&gt;
** если последний символ совпадает с запомненным, стереть его, перейти в начало ленты и повторить с первого шага&lt;br /&gt;
** в случае несовпадения перейти в отвергающее состояние&lt;br /&gt;
&lt;br /&gt;
Формально: &amp;lt;tex&amp;gt;\Sigma = \{0, 1\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Pi = \{0, 1, B\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;Q = \{S, F_0, F_1, B_0, B_1, R \}&amp;lt;/tex&amp;gt;. Таблица функции &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; приведена ниже:&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;5&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 |width=&amp;quot;30&amp;quot;|&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |width=&amp;quot;100&amp;quot;| &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;F_0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_0, 1, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle B_0, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;F_1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, 0, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle F_1, 1, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle B_1, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;B_0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle N, 1, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;B_1&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle N, 0, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, B, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle Y, B, \downarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |-&lt;br /&gt;
 | &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 0, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle R, 1, \leftarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 | &amp;lt;tex&amp;gt;\langle S, B, \rightarrow \rangle&amp;lt;/tex&amp;gt;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
== Варианты машины Тьюринга ==&lt;br /&gt;
В этом разделе приведены различные варианты машин Тьюринга, которые не отличаются от обычных машин Тьюринга по вычислительной мощности.&lt;br /&gt;
&lt;br /&gt;
=== Многодорожечная машина Тьюринга ===&lt;br /&gt;
Машиной Тьюринга с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожками называется вычислитель, аналогичный машине Тьюринга, лишь с тем отличием, что лента состоит из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожек, на каждой из которых записаны символы ленточного алфавита. У многодорожечной машины одна головка, которая за один шаг переходит в одном направлении на всех дорожках одновременно. Соответственно, функция перехода имеет тип &amp;lt;tex&amp;gt;\delta : Q \times \Pi^n \to Q \times \Pi^n \times \{\leftarrow, \rightarrow, \downarrow\}&amp;lt;/tex&amp;gt;. Многодорожечная машина Тьюринга тривиально эквивалентна обычной с ленточным алфавитом &amp;lt;tex&amp;gt;\Pi' = \Pi^n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Машина Тьюринга с полубесконечной лентой ===&lt;br /&gt;
Заменив у машины Тьюринга бесконечную в обе стороны ленту на бесконечную в одну сторону, мы не теряем в вычислительной мощности. По произвольной машине Тьюринга строится двухдорожечная машина с полубесконечной лентой.&lt;br /&gt;
{{Теорема&lt;br /&gt;
|author=&lt;br /&gt;
|statement=Для любой машины Тьюринга существует эквивалентная машина Тьюринга, работающая на полубесконечной ленте.&lt;br /&gt;
|proof=Существует алгоритм, по которому для любой машины Тьюринга может быть построена эквивалентная машина Тьюринга с объявленным свойством. Сначала занумеруем ячейки рабочей ленты машины Тьюринга с ''бесконечной лентой'' следующим образом:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt1.jpg]]&lt;br /&gt;
&lt;br /&gt;
Затем перенумеруем ячейки, и запишем символ &amp;lt;tex&amp;gt;c \in \Pi \setminus \Sigma, B&amp;lt;/tex&amp;gt; в начало ленты, который будет означать границу рабочей зоны:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Наконец, изменим машину Тьюринга, удвоив число её состояний, и изменим сдвиг головки так, чтобы в одной группе состояний работа машины была бы эквивалентна её работе в заштрихованной зоне, а в другой группе состояний машина работала бы так, как исходная машина работает в незаштрихованной зоне. Если при работе машины Тьюринга встретится символ &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, значит головка достигла границы рабочей зоны:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Mt3.jpg]]&lt;br /&gt;
&lt;br /&gt;
Начальное состояние новой машины Тьюринга устанавливается в одной или другой зоне в зависимости от того, в какой части исходной ленты располагалась головка считывания-записи в исходной конфигурации.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Многоленточная машина Тьюринга ===&lt;br /&gt;
В отличие от многодорожечной машины Тьюринга, ленты не зависят друг от друга и головки во время одного шага могу перемещаться по-разному. То есть, функция перехода теперь имеет тип &amp;lt;tex&amp;gt;\delta : Q \times \Pi^n \to Q \times \Pi^n \times \{\leftarrow, \rightarrow, \downarrow\}^n&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Многоленточная машина с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; дорожками эмулируется многодорожечной машиной с &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; дорожками следующим образом: каждая нечётная дорожка соответствует ленте исходной машины, а на каждой чётной дорожке отмечены специальным символом &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt; позиция головки на ленте выше (считаем, что ленты нумеруются сверху вниз).&lt;br /&gt;
&lt;br /&gt;
Каждый шаг исходной машины эмулируется конечной последовательностью шагов построенной машины следующим образом: исходно головка находится в позиции самой левой отметки и идёт вправо до самой правой отметки, запоминая прочитанные около символов &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt; символы в состоянии. Пройдя до самой правой отметки, головка возвращается влево, совершая необходимые действия (переписывая символы около отметок и передвигая сами отметки). После такого прохода головка переходит в следующее состояние, завершая эмуляцию шага.&lt;br /&gt;
&lt;br /&gt;
=== Другие эквивалентные вычислительные формализмы ===&lt;br /&gt;
Существуют также другие формализации понятия алгоритма, которые по вычислительным возможностям эквивалентны машинам Тьюринга:&lt;br /&gt;
* [[Стековые машины, эквивалентность двухстековой машины МТ|стековые машины]]&lt;br /&gt;
* [[Счетчиковые машины, эквивалентность двухсчетчиковой машины МТ|счётчиковые машины]]&lt;br /&gt;
* [[Линейный клеточный автомат, эквивалентность МТ|клеточные автоматы]]&lt;br /&gt;
* [[Возможность порождения формальной грамматикой произвольного перечислимого языка|произвольные формальные грамматики]]&lt;br /&gt;
* [[Лямбда-исчисление|нетипизированное лямбда-исчисление]]&lt;br /&gt;
&lt;br /&gt;
Аланом Тьюрингом было сформулировано следующее утверждение:&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|about=Тезис Чёрча-Тьюринга&lt;br /&gt;
|statement=&lt;br /&gt;
Класс перечислимых языков совпадает с классом языков, перечислимых с помощью машин Тьюринга&lt;br /&gt;
}}&lt;br /&gt;
Иными словами, тезис говорит о том, что любой алгоритм можно запрограммировать на машине Тьюринга.&lt;br /&gt;
&lt;br /&gt;
== Универсальная машина Тьюринга ==&lt;br /&gt;
&lt;br /&gt;
Существует машина Тьюринга, которая принимает на вход закодированное описание произвольной машины и входную строку и эмулирует работу закодированной машины на заданном входном слове. Иными словами, [[Разрешимые (рекурсивные) языки#Пример неразрешимого множества|универсальный язык]] перечислим с помощью машины Тьюринга. Ссылки на явные конструкции универсальных машин Тьюринга приведены ниже.&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf Alan Turing {{---}} On computable numbers, with an application to the Entscheidungsproblem.]&lt;br /&gt;
* [http://www.ccs.neu.edu/home/viola/classes/papers/HennieStearns66.pdf F. C. Hennie, R. E. Stearn {{---}} Two-tape simulation of multitape Turing machines.]&lt;br /&gt;
* [http://www.cs.princeton.edu/theory/index.php/Compbook/Draft Sanjeev Arora, Boaz Barak {{---}} Computational Complexity: A Modern Approach.]&lt;br /&gt;
* [http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.8958 Turlough Neary, Damien Woods {{---}} Four Small Universal Turing Machines.]&lt;br /&gt;
* [http://www.jflap.org/ JFLAP {{---}} ПО для изучения формальных языков, включает в себя эмулятор одноленточных и многоленточных машин Тьюринга с визуальным редактором.]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Теория формальных языков]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.jpg&amp;diff=50808</id>
		<title>Файл:Mt3.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt3.jpg&amp;diff=50808"/>
				<updated>2016-01-07T09:59:01Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: Машина Тьюринга на полубесконечной ленте - переходы&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Машина Тьюринга на полубесконечной ленте - переходы&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt2.jpg&amp;diff=50807</id>
		<title>Файл:Mt2.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt2.jpg&amp;diff=50807"/>
				<updated>2016-01-07T09:05:38Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: Машина Тьюринга на полубесконечной ленте - нумерация ячеек&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Машина Тьюринга на полубесконечной ленте - нумерация ячеек&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt1.jpg&amp;diff=50806</id>
		<title>Файл:Mt1.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Mt1.jpg&amp;diff=50806"/>
				<updated>2016-01-07T09:03:26Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: Машина Тьюринга на полубесконечной ленте&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Машина Тьюринга на полубесконечной ленте&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34998</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34998"/>
				<updated>2014-01-03T16:49:27Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Пример работы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину для всех вершин, в которые есть ребро из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(g, s, t)&amp;lt;/tex&amp;gt; принимает граф &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; в виде списка смежности, начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''countPaths'''(g, v, t)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         '''return''' 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         s = 0&lt;br /&gt;
         '''for''' to '''in''' g[v]&lt;br /&gt;
             s += '''count'''(g, to, t)&lt;br /&gt;
         '''return''' s&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Например, на следующем графе данный алгоритм будет иметь время работы &amp;lt;tex&amp;gt;O(2^{n/2})&amp;lt;/tex&amp;gt;. Если же использовать метод динамичекого программиования, речь о котором пойдет ниже, то асимптотику можно улучшить до &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Dp-countpaths-example.png‎|600px| Пример графа, на котором алгоритм имеет время работы &amp;lt;tex&amp;gt;O(2^{n/2})&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей от вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что есть ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к меньшим подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей из вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать в виде рекурсивной функции с запоминанием. В этом случае значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости и не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''count'''(g, v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         return d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for''' c '''in''' g[v]&lt;br /&gt;
             sum += '''count'''(g, c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(g, s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = '''true'''&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34997</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34997"/>
				<updated>2014-01-03T16:48:44Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Перебор всех возможных путей */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину для всех вершин, в которые есть ребро из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(g, s, t)&amp;lt;/tex&amp;gt; принимает граф &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; в виде списка смежности, начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''countPaths'''(g, v, t)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         '''return''' 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         s = 0&lt;br /&gt;
         '''for''' to '''in''' g[v]&lt;br /&gt;
             s += '''count'''(g, to, t)&lt;br /&gt;
         '''return''' s&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Например, на следующем графе данный алгоритм будет иметь время работы &amp;lt;tex&amp;gt;O(2^{n/2})&amp;lt;/tex&amp;gt;. Если же использовать метод динамичекого программиования, речь о котором пойдет ниже, то асимптотику можно улучшить до &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Dp-countpaths-example.png‎|600px| Пример графа, на котором алгоритм имеет время работы &amp;lt;tex&amp;gt;O(2^{n/2})&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей от вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что есть ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к меньшим подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей из вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать в виде рекурсивной функции с запоминанием. В этом случае значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости и не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''count'''(g, v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         return d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for''' c '''in''' g[v]&lt;br /&gt;
             sum += '''count'''(g, c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(g, s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = '''true'''&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34996</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34996"/>
				<updated>2014-01-03T16:47:22Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Перебор всех возможных путей */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину для всех вершин, в которые есть ребро из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(g, s, t)&amp;lt;/tex&amp;gt; принимает граф &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;, начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''countPaths'''(g, v, t)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         '''return''' 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         s = 0&lt;br /&gt;
         '''for''' to '''in''' g[v]&lt;br /&gt;
             s += '''count'''(g, to, t)&lt;br /&gt;
         '''return''' s&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Например, на следующем графе данный алгоритм будет иметь время работы &amp;lt;tex&amp;gt;O(2^{n/2})&amp;lt;/tex&amp;gt;. Если же использовать метод динамичекого программиования, речь о котором пойдет ниже, то асимптотику можно улучшить до &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Dp-countpaths-example.png‎|600px| Пример графа, на котором алгоритм имеет время работы &amp;lt;tex&amp;gt;O(2^{n/2})&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей от вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что есть ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к меньшим подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей из вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать в виде рекурсивной функции с запоминанием. В этом случае значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости и не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''count'''(g, v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         return d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for''' c '''in''' g[v]&lt;br /&gt;
             sum += '''count'''(g, c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(g, s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = '''true'''&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34995</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34995"/>
				<updated>2014-01-03T16:36:37Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину для всех вершин, в которые есть ребро из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(g, s, t)&amp;lt;/tex&amp;gt; принимает граф &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;, начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''countPaths'''(g, v, t)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         '''return''' 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         s = 0&lt;br /&gt;
         '''for''' to '''in''' g[v]&lt;br /&gt;
             s += '''count'''(g, to, t)&lt;br /&gt;
         '''return''' s&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Например, на следующем графе данный алгоритм будет иметь время работы &amp;lt;tex&amp;gt;O(2^n)&amp;lt;/tex&amp;gt;. Если же использовать метод динамичекого программиования, речь о котором пойдет ниже, то асимптотику можно улучшить до &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Dp-countpaths-example.png‎|600px| Пример графа, на котором алгоритм имеет время работы &amp;lt;tex&amp;gt;O(2^n)&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей от вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что есть ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к меньшим подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей из вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать в виде рекурсивной функции с запоминанием. В этом случае значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости и не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''count'''(g, v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         return d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for''' c '''in''' g[v]&lt;br /&gt;
             sum += '''count'''(g, c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(g, s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = '''true'''&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34994</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34994"/>
				<updated>2014-01-03T16:26:52Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Перебор всех возможных путей */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину для всех вершин, в которые есть ребро из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(g, s, t)&amp;lt;/tex&amp;gt; принимает граф &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;, начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''countPaths'''(g, v, t)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         '''return''' 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         s = 0&lt;br /&gt;
         '''for''' to '''in''' g[v]&lt;br /&gt;
             s += '''count'''(g, to, t)&lt;br /&gt;
         '''return''' s&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Например, на следующем графе данный алгоритм будет иметь время работы &amp;lt;tex&amp;gt;O(2^n)&amp;lt;/tex&amp;gt;. Если же использовать метод динамичекого программиования, речь о котором пойдет ниже, то асимптотику можно улучшить до &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Dp-countpaths-example.png‎|left|thumb|600px| Пример графа, на котором алгоритм имеет время работы &amp;lt;tex&amp;gt;O(2^n)&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей от вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что есть ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к меньшим подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей из вершины &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать в виде рекурсивной функции с запоминанием. В этом случае значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости и не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''count'''(g, v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         return d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for''' c '''in''' g[v]&lt;br /&gt;
             sum += '''count'''(g, c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(g, s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = '''true'''&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Dp-countpaths-example.png&amp;diff=34993</id>
		<title>Файл:Dp-countpaths-example.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Dp-countpaths-example.png&amp;diff=34993"/>
				<updated>2014-01-03T16:16:53Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34854</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34854"/>
				<updated>2013-12-29T18:22:56Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Перебор всех возможных путей */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее с помощью динамики.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех вершин, ребра в которые выходят из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(s, t)&amp;lt;/tex&amp;gt; принимает начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. В глобальной переменной &amp;lt;tex&amp;gt;answer&amp;lt;/tex&amp;gt; содержится ответ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 answer = 0&lt;br /&gt;
 &lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         answer += 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             '''count'''(to)&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     answer = 0&lt;br /&gt;
     count(s)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;\exists&amp;lt;/tex&amp;gt; ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         '''return''' d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             sum += '''count'''(c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34853</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34853"/>
				<updated>2013-12-29T15:30:14Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Перебор всех возможных путей */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее с помощью динамики.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех вершин, ребра в которые выходят из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(s, t)&amp;lt;/tex&amp;gt; принимает начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. В глобальной переменной &amp;lt;tex&amp;gt;answer&amp;lt;/tex&amp;gt; содержится ответ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 answer = 0&lt;br /&gt;
 &lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         answer += 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             '''count'''(to)&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     answer = 0&lt;br /&gt;
     count(s)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе.&lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;\exists&amp;lt;/tex&amp;gt; ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         '''return''' d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             sum += '''count'''(c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34852</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34852"/>
				<updated>2013-12-29T15:29:39Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: описание картинки&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее с помощью динамики.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех вершин, ребра в которые выходят из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(s, t)&amp;lt;/tex&amp;gt; принимает начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. В глобальной переменной &amp;lt;tex&amp;gt;answer&amp;lt;/tex&amp;gt; содержится ответ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 answer = 0&lt;br /&gt;
 &lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         answer += 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             '''count'''(to)&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     answer = 0&lt;br /&gt;
     count(s)&lt;br /&gt;
     return answer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;\exists&amp;lt;/tex&amp;gt; ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         '''return''' d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             sum += '''count'''(c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34851</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34851"/>
				<updated>2013-12-29T15:26:09Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее с помощью динамики.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех вершин, ребра в которые выходят из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(s, t)&amp;lt;/tex&amp;gt; принимает начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. В глобальной переменной &amp;lt;tex&amp;gt;answer&amp;lt;/tex&amp;gt; содержится ответ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 answer = 0&lt;br /&gt;
 &lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         answer += 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             '''count'''(to)&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     answer = 0&lt;br /&gt;
     count(s)&lt;br /&gt;
     return answer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;\exists&amp;lt;/tex&amp;gt; ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         '''return''' d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             sum += '''count'''(c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px| description ]]&lt;br /&gt;
&lt;br /&gt;
Изначально массивы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; инициализированы следующим образом:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || false || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 0 || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
Сначала функция &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершины &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Ответ для нее еще не посчитан (&amp;lt;tex&amp;gt;w[T] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана от вершин &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. Для вершины &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; ответ также не посчитан (&amp;lt;tex&amp;gt;w[3] = false&amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt;count&amp;lt;/tex&amp;gt; будет вызвана уже для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. А вот для них ответ мы уже можем узнать: для &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; он равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; - единствнная вершина, ребро из которой входит в нее. Непосредственно для &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; ответ нам также известен. На текущий момент таблица будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || '''true''' || false || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || '''1''' || 0 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь мы знаем значения для вершин &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, что позволяет вычислить &amp;lt;tex&amp;gt;d[3] = d[2] + d[S] = 2&amp;lt;/tex&amp;gt;. Также обновим значения в массиве &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt;w[3] = true&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || false || true || '''true''' || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 0 || 1 || '''2''' || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В самом начале для вычисления &amp;lt;tex&amp;gt;d[T]&amp;lt;/tex&amp;gt; нам требовались значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. Теперь нам известно значение &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt;, поэтому проследим за тем, как будет вычисляться &amp;lt;tex&amp;gt;d[4]&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = count(3) + count(2) + count(1)&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;w[3] = true, w[2] = true&amp;lt;/tex&amp;gt;, следовательно значения &amp;lt;tex&amp;gt;d[3]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d[2]&amp;lt;/tex&amp;gt; мы уже знаем, и нам необходимо вызвать &amp;lt;tex&amp;gt;count(1)&amp;lt;/tex&amp;gt;. Ответ для этой вершины равен &amp;lt;tex&amp;gt;d[S]&amp;lt;/tex&amp;gt;, так как это единственная вершина, ребро из которой входит в &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Обновим соответствующие значения массивов &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || '''true''' || true || true || false || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || '''1''' || 1 || 2 || 0 || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь нам известны все три значения, требующиеся для вычисления ответа для вершины &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;d[4] = d[3] + d[2] + d[1] = 2 + 1 + 1 = 4&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || '''true''' || false&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || '''4''' || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Наконец, вычислим &amp;lt;tex&amp;gt;d[T] = d[3] + d[4] = 2 + 4 = 6&amp;lt;/tex&amp;gt; и обновим таблицы &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; и&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; cellpadding=&amp;quot;4&amp;quot; border=&amp;quot;1&amp;quot; style=&amp;quot;border-collapse: collapse;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| '''вершина''' || S || 1 || 2 || 3 || 4 || T&lt;br /&gt;
|-&lt;br /&gt;
| '''w''' || true || true || true || true || true || '''true'''&lt;br /&gt;
|-&lt;br /&gt;
| '''d''' || 1 || 1 || 1 || 2 || 4 || '''6'''&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм позволяет вычислить количество путей от какой-либо вершины &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не только до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, но и для любой вершины, лежащей на любом из путей от &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. Для этого достаточно взять значение в соответствующей ячейке &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34762</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34762"/>
				<updated>2013-12-26T22:36:12Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее с помощью динамики.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех вершин, ребра в которые выходят из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;countPaths(s, t)&amp;lt;/tex&amp;gt; принимает начальную вершину &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и конечную вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. В глобальной переменной &amp;lt;tex&amp;gt;answer&amp;lt;/tex&amp;gt; содержится ответ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 answer = 0&lt;br /&gt;
 &lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' v == t&lt;br /&gt;
         answer += 1&lt;br /&gt;
     '''else'''&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;to&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
             '''count'''(to)&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t)&lt;br /&gt;
     answer = 0&lt;br /&gt;
     count(s)&lt;br /&gt;
     return answer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма в худшем случае &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt; таких &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;\exists&amp;lt;/tex&amp;gt; ребро из &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{c}count(c), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 '''count'''(v)&lt;br /&gt;
     '''if''' w[v]&lt;br /&gt;
         '''return''' d[v]&lt;br /&gt;
     '''else'''&lt;br /&gt;
         sum = 0&lt;br /&gt;
         '''for'''(всех &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; смежных с &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;):&lt;br /&gt;
             sum += '''count'''(c)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         '''return''' sum&lt;br /&gt;
 &lt;br /&gt;
 '''countPaths'''(s, t):&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = '''count'''(t)&lt;br /&gt;
     '''return''' answer&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Значение функции &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; считается для каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ end(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма в худшем случае оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество ребер.&lt;br /&gt;
&lt;br /&gt;
== Пример работы ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы алгоритма на следующем графе:&lt;br /&gt;
&lt;br /&gt;
[[Файл: count-path-graph-example.png|thumb|300px| description ]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34560</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34560"/>
				<updated>2013-12-22T13:16:43Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Метод динамического программирования */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан граф, не содержащий циклов, в котором необходимо посчитать количество различных путей от одной вершины до другой.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
* '''Постановка задачи'''&lt;br /&gt;
Дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех детей &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if v == t:&lt;br /&gt;
         ans += 1&lt;br /&gt;
     else:&lt;br /&gt;
         for(child : v):&lt;br /&gt;
             count(child)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; - предок &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Асимптотика алгоритма &amp;lt;tex&amp;gt;O(V + E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество вершин. Функция &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вызывается от каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ begin(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{parent}count(parent), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if w[v]:&lt;br /&gt;
         return d[v]&lt;br /&gt;
     else:&lt;br /&gt;
         sum = 0&lt;br /&gt;
         for(parent : v):&lt;br /&gt;
             sum += count(parent)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         return sum&lt;br /&gt;
 &lt;br /&gt;
  countPaths(s, t):&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = count(t)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Count-path-graph-example.png&amp;diff=34542</id>
		<title>Файл:Count-path-graph-example.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Count-path-graph-example.png&amp;diff=34542"/>
				<updated>2013-12-21T22:01:35Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: Пример графа для задачи о числе путей в ациклическом графе.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пример графа для задачи о числе путей в ациклическом графе.&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34535</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34535"/>
				<updated>2013-12-21T21:36:29Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Решение задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан граф, не содержащий циклов, в котором необходимо посчитать количество различных путей от одной вершины до другой.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
* '''Постановка задачи'''&lt;br /&gt;
Дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех детей &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if v == t:&lt;br /&gt;
         ans += 1&lt;br /&gt;
     else:&lt;br /&gt;
         for(child : v):&lt;br /&gt;
             count(child)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; - предок &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вызывается от каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ begin(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Асимптотика алгоритма &amp;lt;tex&amp;gt;O(V + E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество вершин. Значения функции &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вычисляются один раз для кажой вершины, и каждый раз просматриваются ребра &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{parent}count(parent), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if w[v]:&lt;br /&gt;
         return d[v]&lt;br /&gt;
     else:&lt;br /&gt;
         sum = 0&lt;br /&gt;
         for(parent : v):&lt;br /&gt;
             sum += count(parent)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         return sum&lt;br /&gt;
 &lt;br /&gt;
  countPaths(s, t):&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = count(t)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34534</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34534"/>
				<updated>2013-12-21T21:33:52Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: /* Решение задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан граф, не содержащий циклов, в котором необходимо посчитать количество различных путей от одной вершины до другой.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
* '''Постановка задачи'''&lt;br /&gt;
Дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех детей &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if v == t:&lt;br /&gt;
         ans += 1&lt;br /&gt;
     else:&lt;br /&gt;
         for(child : v):&lt;br /&gt;
             count(child)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; - предок &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вызывается от каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ begin(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Асимптотика алгоритма &amp;lt;tex&amp;gt;O(V + E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество вершин. Значения функции &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вычисляются один раз для кажой вершины, и каждый раз просматриваются ребра &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{parent}count(parent), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if w[v]:&lt;br /&gt;
         return d[v]&lt;br /&gt;
     else:&lt;br /&gt;
         sum = 0&lt;br /&gt;
         for(parent : v):&lt;br /&gt;
             sum += count(parent)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         return sum&lt;br /&gt;
 &lt;br /&gt;
  countPaths(s, t):&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = count(t)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34532</id>
		<title>Задача о числе путей в ациклическом графе</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D1%87%D0%B8%D1%81%D0%BB%D0%B5_%D0%BF%D1%83%D1%82%D0%B5%D0%B9_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC_%D0%B3%D1%80%D0%B0%D1%84%D0%B5&amp;diff=34532"/>
				<updated>2013-12-21T21:32:49Z</updated>
		
		<summary type="html">&lt;p&gt;Nafanya: initial commit&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о числе путей в ациклическом графе''' - одна из классических задач на тему динамического программирования. В этой задаче нам дан граф, не содержащий циклов, в котором необходимо посчитать количество различных путей от одной вершины до другой.&lt;br /&gt;
&lt;br /&gt;
Число таких путей может быть велико даже на небольших графах, поэтому перебор всех возможных вариантов займет много времени. Однако, данную задачу можно решить гораздо быстрее методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
* '''Постановка задачи'''&lt;br /&gt;
Дан ациклический граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и две вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Необходимо посчитать количество путей из вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в вершину &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; по рёбрам графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Решение задачи ==&lt;br /&gt;
&lt;br /&gt;
=== Перебор всех возможных путей за O(''Ans'') ===&lt;br /&gt;
&lt;br /&gt;
Небольшая модификация алгоритма [[Обход в глубину, цвета вершин|обхода в глубину]]. Запустим обход в глубину от вершины &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. При каждом посещении вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; проверим, не является ли она искомой вершиной &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Если это так, то ответ увеличивается на единицу и обход прекращается. В противном случае производится запуск обхода в глубину от всех детей &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, причем он производится независимо от того, были ли эти вершины посещены ранее, или нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if v == t:&lt;br /&gt;
         ans += 1&lt;br /&gt;
     else:&lt;br /&gt;
         for(child : v):&lt;br /&gt;
             count(child)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Время работы данного алгоритма &amp;lt;tex&amp;gt;O(Ans)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;Ans&amp;lt;/tex&amp;gt; - количество путей в графе. &lt;br /&gt;
&lt;br /&gt;
=== Метод динамического программирования ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Можно заметить, что &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; зависит только от вершин, ребра из которых входят в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;P(v) = \sum\limits_{c}P(c)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; - предок &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Мы свели нашу задачу к более мелким подзадачам, причем мы также знаем, что &amp;lt;tex&amp;gt;P(s) = 1&amp;lt;/tex&amp;gt;. Это позволяет решить задачу методом динамического программирования.&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вызывается от каждой вершины один раз, а внутри нее рассматриваются все такие ребра &amp;lt;tex&amp;gt;\{e\ |\ begin(e) = v\}&amp;lt;/tex&amp;gt;. Всего таких ребер для всех вершин в графе &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, следовательно, время работы алгоритма оценивается как &amp;lt;tex&amp;gt;O(V+E)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Асимптотика алгоритма &amp;lt;tex&amp;gt;O(V + E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; - количество вершин графа, &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; - количество вершин. Значения функции &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt; вычисляются один раз для кажой вершины, и каждый раз просматриваются ребра &amp;lt;tex&amp;gt;P(v)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; - стартовая вершина, а &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; - конечная, для нее и посчитаем ответ. Будем поддерживать массив &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;d[v]&amp;lt;/tex&amp;gt; - количество путей до вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и массив &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;w[v] = true&amp;lt;/tex&amp;gt;, если ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; уже посчитан, и &amp;lt;tex&amp;gt;w[v] = false&amp;lt;/tex&amp;gt; в противном случае. Изначально &amp;lt;tex&amp;gt;w[i] = false&amp;lt;/tex&amp;gt; для всех вершин, кроме &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d[s] = 1&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex&amp;gt;count(v)&amp;lt;/tex&amp;gt; будет возвращать ответ для вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Удобнее всего это реализовать с помощью ленивой рекурсии, тогда значения массива &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; будут вычисляться по мере необходимости, а засчет запоминания результатов они не будут считаться лишний раз: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; count(v) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 d[v], &amp;amp; w[v]=true \\&lt;br /&gt;
 \sum\limits_{parent}count(parent), &amp;amp; w[v]=false &lt;br /&gt;
 \end{array}&lt;br /&gt;
 \right.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 count(v):&lt;br /&gt;
     if w[v]:&lt;br /&gt;
         return d[v]&lt;br /&gt;
     else:&lt;br /&gt;
         sum = 0&lt;br /&gt;
         for(parent : v):&lt;br /&gt;
             sum += count(parent)&lt;br /&gt;
         d[v] = sum&lt;br /&gt;
         w[v] = true&lt;br /&gt;
         return sum&lt;br /&gt;
 &lt;br /&gt;
  countPaths(s, t):&lt;br /&gt;
     d[s] = 1&lt;br /&gt;
     w[s] = true&lt;br /&gt;
     answer = count(t)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Nafanya</name></author>	</entry>

	</feed>