<?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=Kirkon</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=Kirkon"/>
		<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/Kirkon"/>
		<updated>2026-04-09T16:35:16Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<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=81136</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=81136"/>
				<updated>2021-07-13T14:56:52Z</updated>
		
		<summary type="html">&lt;p&gt;Kirkon: /* Задача о сумме длин всех путей в дереве */&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;
|definition = Пусть задано взвешенное дерево, с весами, обозначенными как &amp;lt;tex&amp;gt;w_{i,j}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — вершины дерева, соединённые ребром.. Необходимо составить такое [[Теорема_о_максимальном_паросочетании_и_дополняющих_цепях | паросочетание]], чтобы суммарный вес всех рёбер, входящих в него, был максимальным.&lt;br /&gt;
}}&lt;br /&gt;
Для решения данной задачи существует несколько алгоритмов. Например, [[алгоритм_Куна_для_поиска_максимального_паросочетания | алгоритм Куна]], который имеет верхнюю оценку порядка &amp;lt;tex&amp;gt;O \left ( n^3 \right )&amp;lt;/tex&amp;gt;. Но так как нам дано дерево, то можно использовать динамическое программирование, время работы алгоритма с которым улучшается до &amp;lt;tex&amp;gt;O \left ( n \right )&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Обозначим &amp;lt;tex&amp;gt;a[i]&amp;lt;/tex&amp;gt; как паросочетание максимального веса в поддереве с корнем в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-той вершине, при этом &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-тая вершина соединена ребром, входящим в паросочетание, с вершиной, входящей в поддерево &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой вершины; аналогично &amp;lt;tex&amp;gt;b[i]&amp;lt;/tex&amp;gt; {{---}} как паросочетание максимального веса в поддерева с корнем в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-той вершине, но только при этом &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-тая вершина соединена ребром, входящим в паросочетание, с вершиной, не входящей в поддерево &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой вершины; а &amp;lt;tex&amp;gt;c[i]=\max \left ( a[i],b[i] \right )&amp;lt;/tex&amp;gt;, таким образом, ответ на задачу будет находиться в &amp;lt;tex&amp;gt;c[root]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;root&amp;lt;/tex&amp;gt; {{---}} корень дерева. Идея динамического программирования здесь состоит в том, что для того, чтобы найти паросочетание максимального веса с корнем в вершине &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, нам необходимо найти максимальное паросочетание для всех поддеревьев &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой вершины.&lt;br /&gt;
&lt;br /&gt;
Обозначим &amp;lt;tex&amp;gt;Ch(x)&amp;lt;/tex&amp;gt; {{---}} как множество сыновей вершины &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; и будем находить значения &amp;lt;tex&amp;gt;a[x]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b[x]&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
&lt;br /&gt;
Если вершина &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; {{---}} лист, то &amp;lt;tex&amp;gt;a[x]=b[x]=0&amp;lt;/tex&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
в противном же случае&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;a[x]=\max_{y \in Ch(x)}\limits \left ( b[y]+w_{x,y}  +\sum_{\substack{z \neq y\\z \in Ch(x)}} \limits \max \left ( a[z],b[z] \right )\right )&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* &amp;lt;tex&amp;gt;b[x]=\sum_{z \in Ch(x)} \limits \max \left ( a[z], b[z] \right )&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
С учётом того, что &amp;lt;tex&amp;gt;c[i]=\max \left ( a[i],b[i] \right )&amp;lt;/tex&amp;gt;, эти формулы можно переписать как&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt;a[x]=\max_{y \in Ch(x)}\limits \left ( b[y]+w_{x,y}-c[y] \right )+b[x]&amp;lt;/tex&amp;gt;&lt;br /&gt;
* &amp;lt;tex&amp;gt;b[x]=\sum_{z \in Ch(x)} \limits c[z]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь оценим количество операций, необходимых нам для нахождения &amp;lt;tex&amp;gt;c[root]&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;c[i]=\max \left ( a[i],b[i] \right )&amp;lt;/tex&amp;gt;, то для вычисления &amp;lt;tex&amp;gt;c[root]&amp;lt;/tex&amp;gt; необходимо вычислить &amp;lt;tex&amp;gt;a[root]&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;b[root]&amp;lt;/tex&amp;gt;. Для вычисления и того, и другого необходимо время порядка &amp;lt;tex&amp;gt;O \left ( \sum_{x=1}^n \limits \left | Ch(x) \right | \right )=O \left ( n \right )&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;
 &amp;lt;font color = darkgreen&amp;gt;// в основной процедуре вызываем dfs от корня(root), после этого ответ будет хранится в c[root] &amp;lt;/font color = darkgreen&amp;gt;&lt;br /&gt;
 '''function''' dfs(x: '''int''', a: '''int[]''', b: '''int[]''', c: '''int[]''', w: '''int[][]''', Ch: '''int[]'''): &lt;br /&gt;
    '''for''' (i : Ch[x])&lt;br /&gt;
        dfs(i, a, b, c, w, Ch)&lt;br /&gt;
        a[x] = max(a[x], b[i] + w[x][i] - с[i]) &amp;lt;font color = darkgreen&amp;gt;// по формуле выше, но без b[x] (прибавим его один раз в конце) &amp;lt;/font color = darkgreen&amp;gt;&lt;br /&gt;
        b[x] += с[i] &lt;br /&gt;
    a[x] += b[x]                                &amp;lt;font color = darkgreen&amp;gt;// так как в a[x] пока что хранится только на сколько мы можем увеличить ответ если будем использовать вершину x&amp;lt;/font color = darkgreen&amp;gt;                                      &lt;br /&gt;
    c[x] = max(a[x], b[x])&lt;br /&gt;
&lt;br /&gt;
== Задача о сумме длин всех путей в дереве ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Найти сумму длин всех путей в дереве.&lt;br /&gt;
}}&lt;br /&gt;
Решим эту задачу за &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;. Пусть задано подвешенное дерево. Рассмотрим пути проходящие в поддереве вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Во-первых, это пути, не проходящие через эту вершину, то есть все пути в поддеревьях её сыновей. Во-вторых, пути, которые оканчиваются вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. И в-третьих, это пути, проходящие через вершину &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, они начинаются из поддерева одного из сыновей этой вершины и заканчиваются в другом поддереве одного из сыновей вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Теперь подсчитаем пути для каждого варианта. Обозначим &amp;lt;tex&amp;gt; S[v]\ - &amp;lt;/tex&amp;gt; размер поддерева &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; F[v]\ - &amp;lt;/tex&amp;gt; сумма длин всех путей в поддереве вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; G[v]\ - &amp;lt;/tex&amp;gt; сумма длин всех путей начинающихся в поддереве вершины v и оканчивающихся вершиной &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; H[v]\ - &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; S[u] &amp;lt;/tex&amp;gt; = 1, а &amp;lt;tex&amp;gt; G[u] &amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt; H[u] &amp;lt;/tex&amp;gt; = 0.&lt;br /&gt;
# Пути не проходящие через эту вершину. Это просто сумма суммы длин путей для всех поддеревьев детей или &amp;lt;tex&amp;gt; \sum_{x \in Ch(v)} \limits F[x]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Пути оканчивающиеся в вершине &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Рассмотрим ребро, соединяющее вершину &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и одного ее сына, пусть это будет вершина &amp;lt;tex&amp;gt; g &amp;lt;/tex&amp;gt;. Переберем все пути, которые начинаются с этого ребра и идут вниз. Сумма длин всех таких путей будет сумма путей оканчивающихся в &amp;lt;tex&amp;gt; g + S[g] &amp;lt;/tex&amp;gt;, так как суммарная длина путей оканчивающихся в вершине &amp;lt;tex&amp;gt; g &amp;lt;/tex&amp;gt; уже сосчитана и каждый такой путь, которых ровно &amp;lt;tex&amp;gt; S[g] &amp;lt;/tex&amp;gt; мы продлили ребром, соединяющим вершины &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; g &amp;lt;/tex&amp;gt;. Суммарная длина таких путей: &amp;lt;tex&amp;gt; G[v] = \sum_{x \in Ch(v)} \limits {\Bigl(G[x] + S[x]\Bigl)}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Пути проходящие через вершину &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. Рассмотрим двух сыновей этой вершины: &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; y &amp;lt;/tex&amp;gt;. Нам надо подсчитать все пути, которые поднимаются из поддерева &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и затем опускаются в поддерево &amp;lt;tex&amp;gt; y &amp;lt;/tex&amp;gt; и наоборот. То есть по каждому пути, оканчивающимся в вершине &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt; мы пройдем столько раз сколько элементов в поддереве &amp;lt;tex&amp;gt; y &amp;lt;/tex&amp;gt;, следовательно суммарная длина таких путей будет &amp;lt;tex&amp;gt; G[x]S[y] &amp;lt;/tex&amp;gt;. Аналогично, если будем подниматься из поддерева &amp;lt;tex&amp;gt; y &amp;lt;/tex&amp;gt;. Также надо учитывать сколько раз мы проходим по ребрам, соединяющим вершины &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; y &amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt;. Итого для двух вершин &amp;lt;tex&amp;gt; x &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; y &amp;lt;/tex&amp;gt;: &amp;lt;tex&amp;gt; G[x]S[y] + G[y]S[x] + 2S[x]S[y]  &amp;lt;/tex&amp;gt;, следовательно ( &amp;lt;tex&amp;gt; x,y \in Ch(v)&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt; H[v] = \sum_{x,y\ x \ne y} \limits{\Bigl(G[x]S[y] + G[y]S[x] + 2S[x]S[y]\Bigl)} &amp;lt;/tex&amp;gt;. Но такой подсчет испортит асимптотику до &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;. Заметим, что &amp;lt;tex&amp;gt; \sum_{x,y} \limits {\Bigl(G[x]S[y]\Bigl)} = \sum_{x} \limits {G[x]} \sum_{y} \limits {S[y]} &amp;lt;/tex&amp;gt;. Но еще надо учесть, что &amp;lt;tex&amp;gt; x \ne y &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; \sum_{x,y\ x \ne y} \limits{\Bigl(G[x]S[y]\Bigl)} = \sum_{x} \limits {G[x]} \sum_{y} \limits {S[y]} - \sum_{x} \limits {\Bigl(G[x]S[x]\Bigl)} &amp;lt;/tex&amp;gt;. Аналогично для &amp;lt;tex&amp;gt; S[x]S[y] &amp;lt;/tex&amp;gt;. Итак: &amp;lt;tex&amp;gt; H[v] = 2\biggl(\sum_{x} \limits {G[x]} \sum_{y} \limits {S[y]} - \sum_{x} \limits {\Bigl(G[x]S[x]\Bigl)} \biggl) + 2\biggl(\sum_{x} \limits {S[x]} \sum_{y} \limits {S[y]} - \sum_{x} \limits {\Bigl(S[x]S[x]\Bigl)} \biggl) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ответ задачи: &amp;lt;tex&amp;gt; F[v] = \sum_{x \in Ch(v)} \limits F[x] + G[v] + H[v] &amp;lt;/tex&amp;gt;. Асимптотика каждого слагаемого равна &amp;lt;tex&amp;gt;O \left ( \sum_{x=1}^n \limits \left | Ch(x) \right | \right )=O \left ( n \right )&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; — число вершин в дереве, следовательно и время работы самого алгоритма &amp;lt;tex&amp;gt; O \left (n \right ) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Амортизированные оценки для ДП на дереве ==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Пусть какой-либо алгоритм на дереве работает за время &amp;lt;tex&amp;gt;O \left ( \left |Ch \left ( x \right) \right |^k \right )&amp;lt;/tex&amp;gt; для вершины x, тогда время обработки им всего дерева не превышает &amp;lt;tex&amp;gt;O \left ( n^k \right )&amp;lt;/tex&amp;gt;:&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;\forall x \in \left \{ 1 \dots n \right \}: \left | Ch(x) \right | \leqslant n&amp;lt;/tex&amp;gt;, поэтому &amp;lt;tex&amp;gt;\sum_{x=1}^n \limits \left | Ch \left ( x \right ) \right |^k \leqslant \sum_{x=1}^n \limits | Ch \left ( x \right ) | \cdot n^{k-1}=n \cdot n^{k-1}=n^k&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;
*[http://www.mathnet.ru/links/c14aca73a4926918a879905ffcd4ad7a/timb86.pdf В. В. Лепин, Линейный алгоритм для нахождения максимального индуцированного паросочетания наименьшего веса в реберно-взвешенном дереве]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/Паросочетание Википедия — Паросочетание]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Динамическое программирование]]&lt;br /&gt;
[[Категория: Другие задачи динамического программирования]]&lt;br /&gt;
[[Категория:Алгоритмы на графах]]&lt;/div&gt;</summary>
		<author><name>Kirkon</name></author>	</entry>

	</feed>