Динамика по поддеревьям — различия между версиями
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]
Общие принципы динамики по поддеревьям
Самое главное и основное отличие — ответ в одном поддереве может влиять на другие ответы, как в предыдущей задаче влиял выбор корня.