Теоретический материал

Решение задачи о назначениях (Венгерский алгоритм)

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

Лемма 1. Если веса всех ребер графа, инцидентных какой-либо вершине, увеличить (уменьшить) на одно и то же число, то искомое паросочетание является искомым и в новом графе.

Одно из следствий – мы можем считать, что веса всех ребер у нас неотрицательные.

Лемма 2. Если веса всех ребер неотрицательные, и некоторое паросочетание состоит из ребер нулевого веса, то оно искомое.

Схема решения

  for i:= 1 to n do begin

  {каждой вершине одного из множеств находим назначение}

    for j:=1 to n do min[j]:=maxint;

    repeat

      fillchar(new,sizeof(new),false);

      f := dfs(i);{пару ищем только по ребрам нулевого веса}

      if not f then begin

1)      {ищем минимальный элемент в помеченных dfs строках new[i]=true

        среди элементов столбцов не вошедших в текущую цепочку

        (res[j] = 0) or (not new[res[j]])

         обозначим найденный элемент del}

2)      {перестраиваем матрицу так:

         из всех помеченных dfs строк вычитаем del

         ко всем вошедшим в текущую цепочку столбцам прибавляем del

      end;

    until f;

  end;

  for j:= 1 to n do

    writeln(j,' ',res[j])

1

3

2

3

2

1

3

6

4

2

6

8

4

5

2

7

0

2

1

2

2

1

3

6

4

2

6

8

4

5

2

7

0

2

1

2

1

0

2

5

4

2

6

8

4

5

2

7

0

2

1

2

1

0

2

5

2

0

4

6

4

5

2

7

0

3

1

2

0

0

1

4

1

0

3

5

4

6

2

7

0

3

0

1

0

0

0

3

1

0

2

4

4

7

2

7

и т.д.