Динамика по поддеревьям — различия между версиями
Mihver1 (обсуждение | вклад) (→Формулировка) |
Mihver1 (обсуждение | вклад) (→Динамика по поддеревьям) |
||
Строка 12: | Строка 12: | ||
Рассмотрим наше первое состояние, когда еще не выбрана ни одна вершина. В этом случае мы можем сделать две вещи: | Рассмотрим наше первое состояние, когда еще не выбрана ни одна вершина. В этом случае мы можем сделать две вещи: | ||
− | * Разрешить выбирать ребро из корня к ребенку | + | * Разрешить выбирать ребро из корня к ребенку. |
− | * Запретить выбирать ребра из корня | + | * Запретить выбирать ребра из корня. |
Если мы запрещаем, значит можем разрешить всем его детям выбрать ребро из своего корня к своим детям. В ином случае мы можем разрешить не всем детям, а только тем, которые не были выбраны ребром из корня. | Если мы запрещаем, значит можем разрешить всем его детям выбрать ребро из своего корня к своим детям. В ином случае мы можем разрешить не всем детям, а только тем, которые не были выбраны ребром из корня. | ||
===Рекуррентная формула=== | ===Рекуррентная формула=== | ||
− | Обозначим в качестве <tex>dp( | + | Обозначим в качестве <tex>dp(vertex, use\_root)</tex> функцию, возвращающую ответ для поддерева с корнем <tex>u</tex>. |
− | Если <tex> | + | Если <tex>use\_root=1</tex>, то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из <tex>v</tex> в <tex>u</tex> как <tex>w[v,u]</tex> |
− | <tex>dp(u, 0) = \sum_{\text{child}\ v\ of\ u}dp( | + | <tex>dp(u, 0) = \sum_{\text{child}\ v\ of\ u}dp(v, 1)</tex><br> |
− | <tex>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)\ +\ | + | <tex>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\}</tex> |
Заметим, что вторую формулу можно упростить:<br> | Заметим, что вторую формулу можно упростить:<br> | ||
Строка 28: | Строка 28: | ||
Теперь наши формулы имеют вид:<br> | Теперь наши формулы имеют вид:<br> | ||
− | <tex>dp(u, 0) = \sum_{\text{child}\ v\ of\ u}dp( | + | <tex>dp(u, 0) = \sum_{\text{child}\ v\ of\ u}dp(v, 1)</tex><br> |
<tex>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\}</tex> | <tex>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\}</tex> | ||
Строка 53: | Строка 53: | ||
dp[v][root] = max1 | dp[v][root] = max1 | ||
return dp[v][root] | return dp[v][root] | ||
+ | |||
+ | ==Ссылки== | ||
+ | *[http://www.mathnet.ru/links/502560b495f4a3fab62422161e16895f/timb86.pdf Научная статья, решающая похожую задачу из примера (pdf)] |
Версия 23:20, 13 января 2013
Содержание
Динамика по поддеревьям
Главной особенностью динамического программирования по дереву является необходимость учитывать ответы в поддеревьях, т.к. они могут влиять на ответы в других поддеревьях. Рассмотрим для лучшего понимания динамики по поддеревьям задачу о максимальном взвешенном паросочетании в дереве.
Задача о максимальном взвешенном паросочетании на дереве
Формулировка
Пусть дано подвешенное за корень дерево, имеющее веса на каждом из его ребер. Необходимо выбрать такое множество ребер, что бы сумма значений была максимальной и при этом выбранные ребра не имели бы общих вершин. Т.е. необходимо решить задачу о максимальном взвешенном паросочетании.
Решение
Главное отличие этой задачи от других динамически решаемых — ответ в одном поддереве влияет на решение в остальных.
Рассмотрим наше первое состояние, когда еще не выбрана ни одна вершина. В этом случае мы можем сделать две вещи:
- Разрешить выбирать ребро из корня к ребенку.
- Запретить выбирать ребра из корня.
Если мы запрещаем, значит можем разрешить всем его детям выбрать ребро из своего корня к своим детям. В ином случае мы можем разрешить не всем детям, а только тем, которые не были выбраны ребром из корня.
Рекуррентная формула
Обозначим в качестве
функцию, возвращающую ответ для поддерева с корнем . Если , то в этом поддереве мы разрешаем занимать корень, иначе нет. Обозначим вес ребра из в как
Заметим, что вторую формулу можно упростить:
Теперь наши формулы имеют вид:
Заметим, что с помощью этого преобразования мы сократили общее время вычисления с
до .Псевдокод
function calculate(v, root): if dp[v][root] != -1: return dp[v][root] #вернули уже посчитанное значение dp[v][root] sum1 = 0 #случай 1: не берем ребра из корня if root==0: for u in child(v): sum1 += calculate(u, 1) #выполняем мемоизацию dp[v][root] = sum1 return sum1 max1 = dp[v][0] #случай 2: берем какое-то ребро for x in child(v): max1 = max(max1, calculate(x, 0) + calculate(v, 0) - calculate(x, 1) + w[v,x]) # выполняем мемоизацию dp[v][root] = max1 return dp[v][root]