Динамика по поддеревьям — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Задача о паросочетании максимального веса в дереве)
(Псевдокод)
Строка 29: Строка 29:
 
== Псевдокод ==
 
== Псевдокод ==
  
  dfs(int x):
+
  '''int''' dfs('''int''' x):
     for child : Ch[x]
+
     '''for''' (child : Ch[x])
 
         dfs(child);
 
         dfs(child);
         a[x] = max(a[x], b[child] + w[x][child] - с[child]);
+
         a[x] = '''max'''(a[x], b[child] + w[x][child] - с[child]);
 
         b[x] += с[child];
 
         b[x] += с[child];
 
     a[x] += b[x]
 
     a[x] += b[x]
     c[x] = max(a[x], b[x]);  
+
     c[x] = '''max'''(a[x], b[x]);  
 
  dfs(root);
 
  dfs(root);
  return c[root];
+
  '''return''' c[root];
  
 
== Амортизированные оценки для ДП на дереве ==
 
== Амортизированные оценки для ДП на дереве ==

Версия 15:44, 7 декабря 2014

Динамика по поддеревьям

Главной особенностью динамического программирования по поддеревьям является необходимость учитывать ответы в поддеревьях, так как они могут влиять на ответы в других поддеревьях. Рассмотрим для лучшего понимания динамики по поддеревьям задачу о максимальном взвешенном паросочетании в дереве.

Задача о паросочетании максимального веса в дереве

Пусть задано взвешенное дерево, с весами, обозначенными как wi,j, где i и j — вершины дерева, соединённые ребром. Задача: составить такое паросочетание, чтобы суммарный вес всех рёбер, входящих в него, был максимальным.

Для решения данной задачи существует несколько алгоритмов. Например, алгоритм Куна, который имеет верхнюю оценку порядка O(n3). Но так как нам дано дерево, то можно использовать динамическое программирование, время работы алгоритма с которым улучшается до O(n).

Обозначим a[i] как паросочетание максимального веса в поддереве с корнем в i-той вершине, при этом i-тая вершина соединена ребром, входящим в паросочетание, с вершиной, входящей в поддерево i-ой вершины; аналогично b[i] - как паросочетание максимального веса в поддерева с корнем в i-той вершине, но только при этом i-тая вершина соединена ребром, входящим в паросочетание, с вершиной, не входящей в поддерево i-ой вершины; а c[i]=max(a[i],b[i]), таким образом, ответ на задачу будет находиться в c[root], где root - корень дерева. Идея динамического программирования здесь состоит в том, что для того, чтобы найти паросочетание максимального веса с корнем в вершине i, нам необходимо найти максимальное паросочетание для всех поддеревьев i-ой вершины.

Обозначим Ch(x) — как множество сыновей вершины x и будем находить значения a[x] и b[x] следующим образом:

Если вершина x — лист, то a[x]=b[x]=0,

в противном же случае

  • a[x]=maxyCh(x)(b[y]+wx,y+zyzCh(x)max(a[z],b[z])),
  • b[x]=zCh(x)max(a[z],b[z])

С учётом того, что c[i]=max(a[i],b[i]), эти формулы можно переписать как

  • a[x]=maxyCh(x)(b[y]+wx,yc[y])+b[x]
  • b[x]=zCh(x)c[z].


Теперь оценим количество операций, необходимых нам для нахождения c[root]. Так как c[i]=max(a[i],b[i]), то для вычисления c[root] необходимо вычислить a[root], b[root]. Для вычисления и того, и другого необходимо время порядка O(nx=1|Ch(x)|)=O(n), где n — количество вершин в дереве.

Псевдокод

int dfs(int x):
   for (child : Ch[x])
       dfs(child);
       a[x] = max(a[x], b[child] + w[x][child] - с[child]);
       b[x] += с[child];
   a[x] += b[x]
   c[x] = max(a[x], b[x]); 
dfs(root);
return c[root];

Амортизированные оценки для ДП на дереве

Теорема:
Пусть какой-либо алгоритм на дереве работает за время O(|Ch(x)|k) для вершины x, тогда время обработки им всего дерева не превышает O(nk):
Доказательство:
x{1n}:|Ch(x)|n, поэтому nx=1|Ch(x)|knx=1|Ch(x)|nk1=nnk1=nk.

Ссылки