Динамика по поддеревьям — различия между версиями
Mihver1 (обсуждение | вклад) м (→Решение) |
Mihver1 (обсуждение | вклад) (→Динамика по деревьям) |
||
| Строка 1: | Строка 1: | ||
=Динамика по деревьям= | =Динамика по деревьям= | ||
| − | Рассмотрим динамику по дереву на примере задачи о максимальном | + | Рассмотрим динамику по дереву на примере задачи о максимальном взвешенном паросочетании в дереве. |
==Задача о максимальном взвешенном паросочетании на дереве== | ==Задача о максимальном взвешенном паросочетании на дереве== | ||
===Формулировка=== | ===Формулировка=== | ||
| Строка 8: | Строка 8: | ||
===Решение=== | ===Решение=== | ||
[[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]] | [[Файл:parosochetanie.png|100px|right|frame|Максимальное взвешенное паросочетание]] | ||
| − | |||
Главное отличие этой задачи от других динамически решаемых {{---}} ответ в одном поддереве влияет на решение в остальных. | Главное отличие этой задачи от других динамически решаемых {{---}} ответ в одном поддереве влияет на решение в остальных. | ||
Рассмотрим наше первое состояние, когда еще не выбрана ни одна вершина. В этом случае мы можем сделать две вещи: | Рассмотрим наше первое состояние, когда еще не выбрана ни одна вершина. В этом случае мы можем сделать две вещи: | ||
| − | * | + | * Занять корень каким-то ребром |
| − | * Не | + | * Не занимать корень ребрами |
| − | В первом случае мы не сможем рассматривать его детей вовсе | + | В первом случае мы не сможем рассматривать его детей вовсе. В ином случае мы переходим в его поддеревья и выполняем то же самое действие. |
| + | Если мы оставляем корень свободным, значит может разрешить всем его детям иметь в своих поддеревьях занятый корень. В ином случае мы можем разрешить не всем детям, а только тем, которые уже не заняты ребром из корня. | ||
===Рекуррентная формула=== | ===Рекуррентная формула=== | ||
| Строка 26: | Строка 26: | ||
Теперь наши формулы имеют вид:<br> | Теперь наши формулы имеют вид:<br> | ||
<tex>dp(u, 0) = \sum_{\text{child}\ v\ of\ u}dp(w, 1)</tex><br> | <tex>dp(u, 0) = \sum_{\text{child}\ v\ of\ u}dp(w, 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)\ +\ | + | <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>O(n^2)</tex> до <tex>O(n)</tex>. | Заметим, что с помощью этого преобразования мы сократили общее время вычисления с <tex>O(n^2)</tex> до <tex>O(n)</tex>. | ||
| Строка 36: | Строка 36: | ||
#вернули уже посчитанное значение dp[v][root] | #вернули уже посчитанное значение dp[v][root] | ||
sum1 = 0 | sum1 = 0 | ||
| − | #случай 1: не берем | + | #случай 1: не берем ребра из корня |
| − | for u in child(v): | + | if root==0: |
| − | + | for u in child(v): | |
| − | + | sum1 += calculate(u, 1) | |
| − | #случай 2: берем | + | #выполняем мемоизацию |
| − | for | + | 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] = | + | dp[v][root] = max1 |
| − | return dp[v] | + | return dp[v][root] |
| − | |||
| − | |||
==Общие принципы динамики по поддеревьям== | ==Общие принципы динамики по поддеревьям== | ||
Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня. | Самое главное и основное отличие {{---}} ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня. | ||
Версия 21:18, 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]
Общие принципы динамики по поддеревьям
Самое главное и основное отличие — ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.
