<?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=Mihver1</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=Mihver1"/>
		<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/Mihver1"/>
		<updated>2026-06-11T14:06:28Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B_%D0%B8_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F&amp;diff=32010</id>
		<title>Обсуждение:Собственные векторы и собственные значения</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%B2%D0%B5%D0%BA%D1%82%D0%BE%D1%80%D1%8B_%D0%B8_%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5_%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F&amp;diff=32010"/>
				<updated>2013-06-12T12:02:25Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: Новая страница: «Там, где не доказаны леммы, подразумевается не сложное упражнение. В последнем это лишь п...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29664</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29664"/>
				<updated>2013-01-13T21:43:24Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по поддеревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
Заполним изначально массив &amp;lt;tex&amp;gt;dp[V][2]&amp;lt;/tex&amp;gt; числами -1. (&amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; {{---}} число вершин)&lt;br /&gt;
&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]           //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if useRoot == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
        else:                               //случай 2: берем какое-то ребро    &lt;br /&gt;
            max1 = dp[v][0] &lt;br /&gt;
            for (для) всех x из множества детей v:&lt;br /&gt;
                max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
            dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29663</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29663"/>
				<updated>2013-01-13T21:42:43Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
Заполним изначально массив &amp;lt;tex&amp;gt;dp[V][2]&amp;lt;/tex&amp;gt; числами -1. (&amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; {{---}} число вершин)&lt;br /&gt;
&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]           //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if useRoot == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
        else:                               //случай 2: берем какое-то ребро    &lt;br /&gt;
            max1 = dp[v][0] &lt;br /&gt;
            for (для) всех x из множества детей v:&lt;br /&gt;
                max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
            dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29662</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29662"/>
				<updated>2013-01-13T21:38:34Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
Заполним изначально массив &amp;lt;tex&amp;gt;dp[V][2]&amp;lt;/tex&amp;gt; числами -1. (&amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; {{---}} число вершин)&lt;br /&gt;
&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]           //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if useRoot == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
        else:                               //случай 2: берем какое-то ребро    &lt;br /&gt;
            max1 = dp[v][0] &lt;br /&gt;
            for (для) всех x из множества детей v:&lt;br /&gt;
                max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
            dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29660</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29660"/>
				<updated>2013-01-13T21:33:00Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
Заполним изначально массив &amp;lt;tex&amp;gt;dp[V][2]&amp;lt;/tex&amp;gt; числом -1. (&amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; {{---}} число вершин)&lt;br /&gt;
&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if useRoot == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
        else:    &lt;br /&gt;
            max1 = dp[v][0]                 //случай 2: берем какое-то ребро&lt;br /&gt;
            for (для) всех x из множества детей v:&lt;br /&gt;
                max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
            dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29659</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29659"/>
				<updated>2013-01-13T21:32:31Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
Заполним изначально массив dp[V][2] числом -1. (V {{---}} число вершин)&lt;br /&gt;
&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if useRoot == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
        else:    &lt;br /&gt;
            max1 = dp[v][0]                 //случай 2: берем какое-то ребро&lt;br /&gt;
            for (для) всех x из множества детей v:&lt;br /&gt;
                max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
            dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29658</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29658"/>
				<updated>2013-01-13T21:30:48Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
Заполним изначально массив dp[N][2] числом -1.&lt;br /&gt;
&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if useRoot == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
        else:    &lt;br /&gt;
            max1 = dp[v][0]                 //случай 2: берем какое-то ребро&lt;br /&gt;
            for (для) всех x из множества детей v:&lt;br /&gt;
                max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
            dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29657</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29657"/>
				<updated>2013-01-13T21:17:01Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Реализация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] не было посчитанно ранее:&lt;br /&gt;
            return dp[v][useRoot]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if use_root == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
            return sum&lt;br /&gt;
        max1 = dp[v][0]                 //случай 2: берем какое-то ребро&lt;br /&gt;
        for (для) всех x из множества детей v:&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29656</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29656"/>
				<updated>2013-01-13T21:14:20Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Реализация===&lt;br /&gt;
    calculate(v, useRoot):&lt;br /&gt;
        if dp[v][useRoot] != -1:&lt;br /&gt;
            return dp[v][useRoot]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if use_root == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for (для) всех u из множества детей v:&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[v][useRoot] = sum       &lt;br /&gt;
            return sum&lt;br /&gt;
        max1 = dp[v][0]                 //случай 2: берем какое-то ребро&lt;br /&gt;
        for (для) всех x из множества детей v:&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        dp[v][useRoot] = max1          &lt;br /&gt;
        return dp[v][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29654</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29654"/>
				<updated>2013-01-13T20:51:08Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    calculate(vertex, useRoot):&lt;br /&gt;
        if dp[vertex][useRoot] != -1:&lt;br /&gt;
            return dp[vertex][useRoot]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if use_root == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for u in child(vertex):&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[vertex][useRoot] = sum       &lt;br /&gt;
            return sum&lt;br /&gt;
        max1 = dp[vertex][0]&lt;br /&gt;
        for x in child(vertex):              //случай 2: берем какое-то ребро&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[vertex,x])&lt;br /&gt;
        dp[vertex][useRoot] = max1          &lt;br /&gt;
        return dp[vertex][useRoot]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29653</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29653"/>
				<updated>2013-01-13T20:49:17Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    calculate(vertex, use_root):&lt;br /&gt;
        if dp[vertex][root] != -1:&lt;br /&gt;
            return dp[vertex][use_root]      //вернули уже посчитанное значение dp[vertex][root]&lt;br /&gt;
        sum = 0&lt;br /&gt;
        if use_root == 0:                    //случай 1: не берем ребра из корня&lt;br /&gt;
            for u in child(vertex):&lt;br /&gt;
                sum += calculate(u, 1)&lt;br /&gt;
            dp[vertex][use_root] = sum       //выполняем мемоизацию&lt;br /&gt;
            return sum&lt;br /&gt;
        max1 = dp[vertex][0]&lt;br /&gt;
        for x in child(vertex):              //случай 2: берем какое-то ребро&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(vertex, 0) - calculate(x, 1) + w[vertex,x])&lt;br /&gt;
        dp[vertex][use_root] = max1          //выполняем мемоизацию&lt;br /&gt;
        return dp[vertex][use_root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29652</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29652"/>
				<updated>2013-01-13T20:45:59Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по поддеревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29651</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29651"/>
				<updated>2013-01-13T20:43:24Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;vertex&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29645</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29645"/>
				<updated>2013-01-13T20:26:43Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Формулировка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29644</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29644"/>
				<updated>2013-01-13T20:24:54Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Формулировка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0,_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B8_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&amp;diff=29643</id>
		<title>Дискретная математика, алгоритмы и структуры данных</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0,_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%B8_%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D1%8B_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85&amp;diff=29643"/>
				<updated>2013-01-13T20:23:08Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамическое программирование */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
*[[Алгоритм Флойда — Уоршелла|Алгоритм Флойда-Уоршалла построения транзитивного замыкания отношения]]&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;
*[[Представление функции класса DM с помощью медианы]]&lt;br /&gt;
*[[Пороговая функция]]&lt;br /&gt;
&lt;br /&gt;
== Схемы из функциональных элементов ==&lt;br /&gt;
*[[Реализация булевой функции схемой из функциональных элементов]]&lt;br /&gt;
*[[Cумматор]]&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;
*[[Алгоритм LZW]]&lt;br /&gt;
*[[Алгоритмы LZ77 и LZ78]]&lt;br /&gt;
*[[Преобразование Барроуза-Уиллера]]&lt;br /&gt;
*[[Обратное преобразование Барроуза-Уиллера]]&lt;br /&gt;
*[[Преобразование MTF]]&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;
*[[Коды антигрея]]&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;
*[[Кратчайший путь в ациклическом графе]]&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;
*[[Meet-in-the-middle]]&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;
*[[Энтропия случайного источника]]&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;
= Второй семестр =&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;
&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;
* [[2-3 дерево]]&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Декартово дерево по неявному ключу]]&lt;br /&gt;
* [[Splay-дерево]]&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;
* [[Встречное дерево Фенвика]]&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;
* [[Сортировка кучей]]&lt;br /&gt;
* [[Быстрая сортировка]]&lt;br /&gt;
* [[Сортировка слиянием]]&lt;br /&gt;
* [[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
* [[Теорема о нижней оценке для сортировки сравнениями]]&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Сортировка подсчетом сложных объектов]]&lt;br /&gt;
* [[Цифровая сортировка]]&lt;br /&gt;
* [[Карманная сортировка]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики за линейное время]]&lt;br /&gt;
* [[Сортировка Хана]]&lt;br /&gt;
&lt;br /&gt;
== Сортирующие сети ==&lt;br /&gt;
* [[Сортирующие сети]]&lt;br /&gt;
* [[0-1 принцип | Проверка сети компараторов на то, что она сортирующая. 0-1 принцип]]&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;
* [[Основные определения теории графов|Основные определения: граф, ребро, вершина, степень, петля, путь, цикл]]&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;
* [[Граф блоков-точек сочленения]]&lt;br /&gt;
* [[Точка сочленения, эквивалентные определения]]&lt;br /&gt;
* [[Мост, эквивалентные определения]]&lt;br /&gt;
* [[k-связность]]&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;
* [[Гамильтоновы графы]]&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;
* [[Непланарность K5 и K3,3|Непланарность &amp;lt;tex&amp;gt;K_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;K_{3,3}&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;
* [[Двудольные графы и раскраска в 2 цвета]]&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;
* [[Использование обхода в глубину для поиска цикла в ориентированном графе]]&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;
* [[Алгоритм A*]]&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;
* [[Связь вершинного покрытия и независимого множества]]&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;
* [[Метод проталкивания предпотока]]&lt;br /&gt;
* [[Алгоритм &amp;quot;поднять-в-начало&amp;quot;]]&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;
* [[Основные определения, связанные со строками]]&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;
* [[Z-функция]]&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;
* [[Алгоритм поиска подстроки в строке с помощью суффиксного массива]]&lt;br /&gt;
&lt;br /&gt;
== Задача о наименьшем общем предке ==&lt;br /&gt;
* [[Метод двоичного подъема]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Алгоритм Фарака-Колтона и Бендера]] (решение +/-1 RMQ с помощью метода четырех русских)&lt;br /&gt;
* [[Алгоритм Шибера-Вишкина]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&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;
* [[Лемма о паросочетании в графе замен]]&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;
* [[Flow shop]]&lt;br /&gt;
* [[1precpmtnrifmax|&amp;lt;tex&amp;gt;1 \mid prec, pmtn, r_i \mid f_{\max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QpmtnCmax|&amp;lt;tex&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QpmtnriLmax|&amp;lt;tex&amp;gt;Q \mid pmtn, r_{i} \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[P2precpi1Lmax|&amp;lt;tex&amp;gt;P2 \mid prec, p_i = 1 \mid L_{\max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[R2Cmax|&amp;lt;tex&amp;gt;R2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[O2Cmax|&amp;lt;tex&amp;gt;O2 \mid \mid C_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[PpmtnriLmax|&amp;lt;tex&amp;gt;P \mid pmtn, r_i \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Opi1sumu|&amp;lt;tex&amp;gt;O \mid p_{ij} = 1 \mid \sum U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[Fpij1sumwu|&amp;lt;tex&amp;gt;F \mid p_{ij} = 1 \mid \sum w_i U_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ripi1sumwc|&amp;lt;tex&amp;gt;1 \mid r_{i}, p_i=1\mid \sum w_{i}C_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1ridipi1|&amp;lt;tex&amp;gt;1 \mid r_{i}, d_{i}, p_{i} = 1 \mid -&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1outtreesumwc | &amp;lt;tex&amp;gt;1 \mid outtree \mid \sum w_i C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[1pi1sumwu|&amp;lt;tex&amp;gt;1 \mid p_{i} = 1 \mid \sum w_{i}U_{i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[QSumCi|&amp;lt;tex&amp;gt;Q\mid\mid\sum{C_i}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[J2pij1Lmax| &amp;lt;tex&amp;gt;J2\mid p_{ij} = 1\mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[P1sumu|&amp;lt;tex&amp;gt;1 \mid \mid \sum U_{i}&amp;lt;/tex&amp;gt;]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29642</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29642"/>
				<updated>2013-01-13T20:22:05Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29641</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29641"/>
				<updated>2013-01-13T20:20:27Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по поддеревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(vertex, use\_root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;use\_root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;w[v,u]&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ w[u, x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(v, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29637</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29637"/>
				<updated>2013-01-13T19:59:11Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Формулировка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень. Иначе нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29629</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29629"/>
				<updated>2013-01-13T18:39:51Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по деревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень. Иначе нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29628</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29628"/>
				<updated>2013-01-13T18:39:27Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по деревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень. Иначе нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29627</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29627"/>
				<updated>2013-01-13T18:36:39Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Решение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень. Иначе нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29626</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29626"/>
				<updated>2013-01-13T18:34:51Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Формулировка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень. Иначе нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29625</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29625"/>
				<updated>2013-01-13T18:29:58Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt;, то в этом поддереве мы разрешаем занимать корень. Иначе нет.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29624</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29624"/>
				<updated>2013-01-13T18:28:55Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Решение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и использующего корень, если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt; и наоборот.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29622</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29622"/>
				<updated>2013-01-13T18:25:00Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по деревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и использующего корень, если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt; и наоборот.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29620</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29620"/>
				<updated>2013-01-13T18:20:53Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
Обозначим в качестве &amp;lt;tex&amp;gt;dp(u, root)&amp;lt;/tex&amp;gt; функцию, возвращающую ответ для поддерева с корнем &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и использующего корень, если &amp;lt;tex&amp;gt;root=1&amp;lt;/tex&amp;gt; и наоборот.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29619</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29619"/>
				<updated>2013-01-13T18:18:32Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Общие принципы динамики по поддеревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29617</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29617"/>
				<updated>2013-01-13T18:18:00Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по деревьям */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ w[u,x]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем ребра из корня&lt;br /&gt;
        if root==0:&lt;br /&gt;
            for u in child(v):&lt;br /&gt;
                sum1 += calculate(u, 1)&lt;br /&gt;
            #выполняем мемоизацию&lt;br /&gt;
            dp[v][root] = sum1&lt;br /&gt;
            return sum1&lt;br /&gt;
        max1 = dp[v][0]&lt;br /&gt;
        #случай 2: берем какое-то ребро&lt;br /&gt;
        for x in child(v):&lt;br /&gt;
            max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x])&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v][root] = max1&lt;br /&gt;
        return dp[v][root]&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29615</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29615"/>
				<updated>2013-01-13T18:05:44Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Решение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ a[u,w]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u, 1)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29614</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29614"/>
				<updated>2013-01-13T18:05:13Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Задача о максимальном независимом множестве на дереве */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:parosochetanie.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ a[u,w]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u, 1)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Parosochetanie.png&amp;diff=29612</id>
		<title>Файл:Parosochetanie.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:Parosochetanie.png&amp;diff=29612"/>
				<updated>2013-01-13T18:03:55Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: загружена новая версия «Файл:Parosochetanie.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Parosochetanie.png&amp;diff=29609</id>
		<title>Файл:Parosochetanie.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:Parosochetanie.png&amp;diff=29609"/>
				<updated>2013-01-13T17:58:16Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29603</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29603"/>
				<updated>2013-01-13T17:45:00Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Формулировка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u, 1)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29599</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29599"/>
				<updated>2013-01-13T17:43:28Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v, root):&lt;br /&gt;
        if dp[v][root] != -1:&lt;br /&gt;
            return dp[v][root]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v][root]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u, 1)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29596</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29596"/>
				<updated>2013-01-13T17:34:20Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что вторую формулу можно упростить:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1) = dp(u, 0) - dp(x, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь наши формулы имеют вид:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ dp(u, 0) - dp(x, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с &amp;lt;tex&amp;gt;O(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;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29594</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29594"/>
				<updated>2013-01-13T17:27:16Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29592</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29592"/>
				<updated>2013-01-13T17:25:03Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(v, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29591</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29591"/>
				<updated>2013-01-13T17:20:38Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;dp(u, 0) = \sum_{\text{child}\ v\  of\  u}dp(w, 1)&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;dp(u, 1) = \max\left\{dp(u, 0),\ \max_{\text{child}\ x\ of\ u}\{dp(x, 0)\ +\ \sum_{\text{child}\ v\ of\ u; \ v \ne x }dp(x, 1)\ +\ a[u]  \}\right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29573</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29573"/>
				<updated>2013-01-13T16:06:28Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;I(u) = \max\left\{a[u]\ +\  \sum_{\text{grandchild}\ w\  of\  u}I(w),\ \sum_{\text{child}\  w\  of\  u}I(w) \right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29571</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29571"/>
				<updated>2013-01-13T16:02:05Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Решение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Максимальный независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex dpi=180&amp;gt;I(u) = \max\left\{a[u]\ +\  \sum_{\text{grandchild}\ w\  of\  u}I(w),\ \sum_{\text{child}\  w\  of\  u}I(w) \right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29570</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29570"/>
				<updated>2013-01-13T16:00:44Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Рекуррентная формула */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex dpi=180&amp;gt;I(u) = \max\left\{a[u]\ +\  \sum_{\text{grandchild}\ w\  of\  u}I(w),\ \sum_{\text{child}\  w\  of\  u}I(w) \right\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29568</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29568"/>
				<updated>2013-01-13T16:00:16Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Динамика по дереву */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по деревьям=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
==Задача о максимальном независимом множестве на дереве==&lt;br /&gt;
===Формулировка===&lt;br /&gt;
Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
===Решение===&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Независимый набор из красных вершин]]&lt;br /&gt;
Давайте заметим, что в случае дерева эта задача имеет решение методом динамического программирования, в отличии от общего случая на произвольном множестве. Это обобщение относится к классу NP-полных задач.&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;
&amp;lt;tex&amp;gt;I(u) = \max\left\{a[u]\ +\  \sum_{\text{grandchild}\ w\  of\  u}I(w),\ \sum_{\text{child}\  w\  of\  u}I(w) \right\},&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
    function calculate(v):&lt;br /&gt;
        if dp[v] != -1:&lt;br /&gt;
            return dp[v]&lt;br /&gt;
            #вернули уже посчитанное значение dp[v]&lt;br /&gt;
        sum1 = 0&lt;br /&gt;
        #случай 1: не берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            sum1 += calculate(u)&lt;br /&gt;
        sum2 = a[v]&lt;br /&gt;
        #случай 2: берем корень&lt;br /&gt;
        for u in child(v):&lt;br /&gt;
            for t in child(u): # считаем, что у нас нет ребер наверх, к корню&lt;br /&gt;
                sum2 += calculate(t)&lt;br /&gt;
        # выполняем мемоизацию&lt;br /&gt;
        dp[v] = max(sum1, sum2)&lt;br /&gt;
        return dp[v]&lt;br /&gt;
&lt;br /&gt;
child(v) -- возвращает детей вершины v&lt;br /&gt;
&lt;br /&gt;
==Общие принципы динамики по поддеревьям==&lt;br /&gt;
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29554</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29554"/>
				<updated>2013-01-13T15:25:39Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Динамика по дереву=&lt;br /&gt;
&lt;br /&gt;
Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
{{Определение&lt;br /&gt;
|neat = 1 - параметр нужен для того, чтобы определение не растягивалось на всю страницу(не обязательно)&lt;br /&gt;
|definition=Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын). &lt;br /&gt;
}}&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Независимый набор из красных вершин]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Independent_set_tree.png&amp;diff=29550</id>
		<title>Файл:Independent set tree.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:Independent_set_tree.png&amp;diff=29550"/>
				<updated>2013-01-13T15:20:40Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: загружена новая версия «Файл:Independent set tree.png»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29549</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=29549"/>
				<updated>2013-01-13T15:18:44Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Рассмотрим динамику по дереву на примере задачи о максимальном независимом множестве в дереве.&lt;br /&gt;
[[Файл:Independent_set_tree.png|100px|right|frame|Независимый набор из красных вершин]]&lt;br /&gt;
{{Определение&lt;br /&gt;
|neat = 1 - параметр нужен для того, чтобы определение не растягивалось на всю страницу(не обязательно)&lt;br /&gt;
|definition=Пусть дано подвешенное за корень дерево, имеющее веса на каждой из ее вершин. Необходимо выбрать такое множество вершин, что бы сумма значений была максимальной и при этом выбранные вершины не являлись бы друг-другу соседями (отец-сын).&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Independent_set_tree.png&amp;diff=29548</id>
		<title>Файл:Independent set tree.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:Independent_set_tree.png&amp;diff=29548"/>
				<updated>2013-01-13T15:17:20Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Mihver1</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_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86&amp;diff=28364</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_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B5_%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86&amp;diff=28364"/>
				<updated>2012-12-23T16:43:26Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: /* Оптимизации динамическим программированием */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о порядке перемножения матриц''' (англ. ''chain matrix multiplication'') — классическая задача, которая может быть решена с помощью динамического программирования. В этой задаче нам дается последовательность матриц, в которой мы хотим найти самый эффективный способ их перемножения.&lt;br /&gt;
&lt;br /&gt;
У нас есть множество способов перемножить матрицы, потому что операция перемножения ассоциативна. Другими словами, нет разницы в каком порядке расставляются скобки между множителями, результат будет один и тот же.  &lt;br /&gt;
&lt;br /&gt;
[[Правильные скобочные последовательности | Расстановок скобок]] достаточно много и их количество очень быстро растет. Точное количество всевозможных вариантов равно ''n''–ому [http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%9A%D0%B0%D1%82%D0%B0%D0%BB%D0%B0%D0%BD%D0%B0 числу Каталана]. &lt;br /&gt;
Однако, порядок в котором расставляются скобки между матрицами повлияет на количество арифметических операций, которые потребуются на вычисление ответа, или, другими словами, на ''эффективность''.&lt;br /&gt;
 &lt;br /&gt;
Например, предположим, что А = (10 &amp;amp;times; 30), B = (30 &amp;amp;times; 5), C = (5 &amp;amp;times; 60). Тогда:&lt;br /&gt;
&lt;br /&gt;
:(''AB'')''C'' = (10&amp;amp;times;30&amp;amp;times;5) + (10&amp;amp;times;5&amp;amp;times;60)  = 1500 + 3000 = 4500 операций&lt;br /&gt;
:''A''(''BC'') = (30&amp;amp;times;5&amp;amp;times;60) + (10&amp;amp;times;30&amp;amp;times;60) = 9000 + 18000 = 27000 операций.&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;
Или другими словами, давайте обозначим через &amp;lt;tex&amp;gt;f(i, j)&amp;lt;/tex&amp;gt; минимальное количество скалярных умножений для вычисления матрицы &amp;lt;tex&amp;gt;M_{i..j}&amp;lt;/tex&amp;gt;,  то получаем следующее рекуррентное соотношение:&lt;br /&gt;
&amp;lt;tex&amp;gt; f(i,j) = \left \{ &lt;br /&gt;
\begin{array}{ll}&lt;br /&gt;
 0, &amp;amp; i=j \\&lt;br /&gt;
 min(f(i,k) + f(k+1,j) + p_{i-1}p_kp_j | i \le k &amp;lt; j) &amp;amp; i &amp;lt; j &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;tex&amp;gt;M_{i..j}&amp;lt;/tex&amp;gt; при i=j не нужно ничего делать — это и есть сама матрица &amp;lt;tex&amp;gt;M_i&amp;lt;/tex&amp;gt;. При нетривиальном случае мы перебираем все точки разбиения матрицы &amp;lt;tex&amp;gt;M_{i..j}&amp;lt;/tex&amp;gt; на матрицы &amp;lt;tex&amp;gt;M_{i..k}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_{k+1..j}&amp;lt;/tex&amp;gt;, ищем количество операций, необходимое чтобы их получить и затем перемножаем для получения матрицы &amp;lt;tex&amp;gt;M_{i..j}&amp;lt;/tex&amp;gt;.(Оно будет равно кол-ву операций, потраченное на решение подзадач + стоимость умножения матриц &amp;lt;tex&amp;gt;M_{i..k}M_{k+1..j}&amp;lt;/tex&amp;gt;). Считаем, что размеры матриц заданы в массиве &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и размер матрицы &amp;lt;tex&amp;gt;M_i&amp;lt;/tex&amp;gt; равен &amp;lt;tex&amp;gt;p_{i-1} \times p_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Чтобы привести пример, давайте вернемся к нашим матрицам. Если у нас есть четыре матрицы ''ABCD'', то мы посчитаем для (''A'')(''BCD''), (''AB'')(''CD''), и (''ABC'')(''D''), делая рекурсивные вызовы на отрезках ''ABC'', ''AB'', ''CD'', и ''BCD'', чтобы найти минимальную стоимость. Потом среди них выбираем лучший вариант. Так же, этот алгоритм дает не только минимальную стоимость, но и показывает наилучший способ перемножения матриц: нужно только сгрупировать тем же образом матрицы, каким дается нам минимальная стоимость.&lt;br /&gt;
&lt;br /&gt;
Однако, если применить этот алгоритм, то обнаружим, что он работает также медленно, как и наивный способ перебирания всех скобочных последовательностей. Делается значительное количество ненужной работы. Например, в выше описанном алгоритме, осуществляется рекурсивный вызов, чтобы найти наилучшую стоимость для подсчета ''ABC'' и ''AB''. Но нахождение наилучшей стоимости для подсчета ''ABC'' так же требует нахождения лучшей стоимости для ''AB''. Так как рекурсия растет вглубь все больше и больше, то и число ненужных повторений увеличивается. Итоговая асимптотика, как было сказано выше, равняется ''n''–ому [http://ru.wikipedia.org/wiki/%D0%A7%D0%B8%D1%81%D0%BB%D0%B0_%D0%9A%D0%B0%D1%82%D0%B0%D0%BB%D0%B0%D0%BD%D0%B0 числу Каталана], да плюс вычисление для каждой правильной скобочной последовательности ''затрат'' на перемножение (то есть &amp;lt;tex&amp;gt;O(n \cdot C_n)&amp;lt;/tex&amp;gt;). &amp;lt;!--&amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt;­-ое число Каталана равняется &amp;lt;tex&amp;gt;  \frac{1}{n+1}{2 n \choose n} &amp;lt;/tex&amp;gt; или асимптотически &amp;lt;tex&amp;gt; \frac{4^n}{n^{3/2}\sqrt{\pi}} &amp;lt;/tex&amp;gt;.--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Оптимизации динамическим программированием ===&lt;br /&gt;
Одно из простых решений — это ''мемоизация'' (или ленивые вычисления). Каждый раз, когда считаем минимальную стоимость перемножения определенной подпоследовательности, давайте запоминать ответ. Если мы когда либо захотим посчитать это ещё раз, то уже будет иметь ответ и не будем пересчитывать. Поскольку существует всего &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; подотрезков, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — это количество матриц, то память занимаемая программой будет не так велика. С помощью запоминания ответа мы уменьшили асимптотику алгоритма (перебор) с &amp;lt;tex&amp;gt;O(n \cdot C_n)&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;O(n^3)&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;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int dp[][];&lt;br /&gt;
int v[];&lt;br /&gt;
// dp[i][j] — меморизация на отрезке [i, j)&lt;br /&gt;
// Массив v[] — хранит все размеры матриц по порядку&lt;br /&gt;
// Так как у нас размеры соседних матриц по вертикали и горизонтали совпадают, то они занесены в этот массив однократно&lt;br /&gt;
int matrixChainMultiplication(int l, int r)&lt;br /&gt;
{&lt;br /&gt;
	//l — включая в отрезок&lt;br /&gt;
	//r — исключая из отрезка&lt;br /&gt;
	if dp[l][r] == -1 		//Если значение динамики не посчитано&lt;br /&gt;
		if l == r - 1&lt;br /&gt;
			dp[l][r] = 0;	//Если у нас подотрезок длины 1, то количество операций для перемножения равно нулю&lt;br /&gt;
		else&lt;br /&gt;
			dp[l][r] = infinity;&lt;br /&gt;
			for (int i = l + 1; i &amp;lt; r; i++)&lt;br /&gt;
				dp[l][r] = min(dp[l][r], v[l] * v[i] * v[r - 1] + matrixChainMultiplication(l, i) + matrixChainMultiplication(i, r));&lt;br /&gt;
	return dp[l][r];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
&lt;br /&gt;
* Английская википедиа [http://en.wikipedia.org/wiki/Matrix_chain_multiplication Matrix chain multiplication]&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория:Динамическое_программирование]]&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=28066</id>
		<title>Динамика по поддеревьям</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA%D0%B0_%D0%BF%D0%BE_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F%D0%BC&amp;diff=28066"/>
				<updated>2012-12-19T20:09:45Z</updated>
		
		<summary type="html">&lt;p&gt;Mihver1: Создана основа статьи.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TODO:&lt;br /&gt;
* Merge со статьей berkeley&lt;br /&gt;
* Добавить еще примеры&lt;br /&gt;
* Конспект с лекции. Добавить затронутые темы.&lt;br /&gt;
&lt;br /&gt;
Дерево {{---}} очередная структура данных, на которой можно увидеть принцип разбиения решения на подзадачи. Представьте дерево &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; с &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; вершинами. Так как в поддеревья &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; входят все потомки корня, то поддеревьев в &amp;lt;tex&amp;gt;T&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;
Структура дерева сама подсказывает решение задачи: Обозначим корнем дерева любую вершину и назовем её &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;I(u)&amp;lt;/tex&amp;gt; обозначает размер максимального независимого множества вершин поддерева, корнем которого является вершина &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;. Тогда ответом на задачу будет являться &amp;lt;tex&amp;gt;I(r)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Нетрудно видеть, что если мы включаем вершину ''u'' в максимальное независимое множество, то его [[Мощность множества|мощность]] увеличивается на 1, но его детей мы брать не можем (так как они соединены ребром с вершиной ''u''); если же мы не включаем эту вершину, то мощность максимального независимого множества будет равна сумме размеров независимых множеств детей этой вершины. Остается только выбрать максимум из этих двух вариантов, чтобы получить решение задачи:&lt;br /&gt;
: &amp;lt;tex&amp;gt;I(u) = \max\left\{1\ +\  \sum_{\text{grandchild}\ w\  of\  u}I(w),\ \sum_{\text{child}\  w\  of\  u}I(w) \right\},&amp;lt;/tex&amp;gt;&lt;br /&gt;
где grandchild обозначает всякого «внука» вершины, а child обозначает всякого потомка вершины.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
Считаем, что в вершине u хранится &amp;lt;tex&amp;gt;I(u)&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
   get_independent_set(Node u)     &lt;br /&gt;
       если I(u) уже посчитано, то возвратить I(u)&lt;br /&gt;
       //мощность множества, которое можно получить, если не брать вершину u&lt;br /&gt;
       children_sum = 0&lt;br /&gt;
       //мощность множества, которое можно получить, если взять вершину u&lt;br /&gt;
       grandchildren_sum = 0&lt;br /&gt;
       //цикл по всем детям&lt;br /&gt;
       for i := 1 to child_num do&lt;br /&gt;
          children_sum = children_sum + get_independent_set(children[i])&lt;br /&gt;
       //цикл по всем внукам&lt;br /&gt;
       for i:= 1 to grandchildren_num&lt;br /&gt;
          grandchildren_sum = grandchildren_sum + get_independent_set(grandchildren[i])&lt;br /&gt;
       //запоминаем, чтобы не персчитывать ещё раз&lt;br /&gt;
       I(u) = max(1 + grandchildren_sum, children_sum)&lt;br /&gt;
       возвратить I(u)&lt;br /&gt;
&lt;br /&gt;
Вызов get_independent_set(''r'') даст ответ на задачу. Время выполнения алгоритма, очевидно, &amp;lt;tex&amp;gt;O(|V| + |E|)&amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Mihver1</name></author>	</entry>

	</feed>