Скачиваний:
32
Добавлен:
02.05.2014
Размер:
436.22 Кб
Скачать

На первом месте в пометке будет стоять символ , т.е. пометка будет такой: , где число еще нужно найти. Положим

.

Пусть теперь такое ребро, у которого пометку имеет конец, т.е. вершина имеет пометку . Если , то пометку у вершины не выставляют; если же , то вершина получает пометку , где

.

Процедура расстановки пометок в соответствии с Шагом 2 проводится до тех пор, пока не окажется помеченной вершина , или до тех пор, пока не выяснится, что вершину пометить невозможно. Можно доказать, что в последнем случае поток , с помощью которого проводился весь Шаг 2, имеет максимальную возможную величину, и задача решена.

Если же вершина оказалась помеченной, то переходим к следующему шагу. Отметим принципиальную подробность: если вершина оказалась помеченной, то число, фигурирующее в пометке, обязательно положительно.

Шаг 3. Пусть вершина имеет пометку . Мы изменим сейчас поток на не-скольких ребрах данного графа, в результате чего получится новый стационарный поток из источника в сток , величина которого будет на (это число указано в пометке стока ) больше величины потока .

Если вершина имеет пометку , то на ребре изменим поток , прибавив к его значению на этом ребре число . Если вершина имеет пометку , то на ребре изменим поток , вычитая из его значения на этом ребре число .

Затем перейдем к вершине и проделаем то же, что только что делалось относительно вершины ; при этом прибавлять или вычитать будем прежнее число . Продолжая так, в соответствии с пометками, отбирать ребра графа и менять на них значение потока (на каждом отбираемом ребре - на одно и то же число !), мы придем к источнику . Это будет означать завершение изменения потока. Можно доказать, что полученный в результате поток является стационарным и его величина на больше величины исходного потока .

Затем нужно повторить все сначала с уже новым базовым стационарным потоком.

Пример. Найти максимальный стационарный поток из в в следующей сети (числа у стрелок означают пропускную способность):

Считаем, что исходный стационарный поток тождественно равен нулю. Проставляем пометку около вершины : она такова - . Выбираем далее для пометки вершину ; соответствующая пометка: . Выбираем далее для пометки вершину ; соответствующая пометка: . Теперь появилась возможность пометить и вершину ; соответствующая пометка : .

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

Новый поток имеет величину 1, он стационарен с источником и стоком . Повторим теперь процедуру сначала, стремясь поставить пометку к стоку .

Вершину пометим пометкой . Далее пометим вершину ; соответствующая пометка: . Далее пометим вершину ; соответствующая пометка: . Теперь пометим вершину ; соответствующая пометка: . Теперь снова увеличим на 1 значения потока на ребрах . Новый поток будет тоже стационарен, но уже величины 2.

Вновь поставим пометку у вершины и попытаемся увеличить имеющийся стационарный поток величины 2.

Пометим вершину ; соответствующая пометка: . Далее пометим вершину ; соответствующая пометка: . Далее пометим вершину ; соответствующая пометка: . Вновь изменим поток на 1: прибавим 1 к значениям прежнего потока на ребрах ,

. Вновь полученный поток имеет величину 3.

Дальнейшие попытки достигнуть пометками вершину не имеют успеха. Следовательно, максимальный стационарный поток найден.

6

0 5

0 16 0 0 13 0

0 0 12 0 6 0

0 0 0 0 9 20

0 0 7 0 0 4

0 0 0 14 0 0

0 0 0 0 0 0

Результат: 23

#include <memory.h>

#include <stdio.h>

const int MAX_VERTICES = 40;

int NUM_VERTICES; // число вершин в графе

const int INFINITY = 10000; // условное число обозначающее бесконечность

// f - массив садержащий текушее значение потока

// f[i][j] - поток текущий от вершины i к j

int f[MAX_VERTICES][MAX_VERTICES];

// с - массив содержащий вместимоти ребер,

// т.е. c[i][j] - максимальная величину потока способная течь по ребру (i,j)

int c[MAX_VERTICES][MAX_VERTICES];

// набор вспомогательных переменных используемых функцией FindPath - обхода в ширину

// Flow - значение потока чарез данную вершину на данном шаге поиска

int Flow[MAX_VERTICES];

// Link используется для нахождения собственно пути

// Link[i] хранит номер предыдущей вешины на пути i -> исток

int Link[MAX_VERTICES];

int Queue[MAX_VERTICES]; // очередь

int QP, QC; // QP - указатель начала очереди и QC - число эл-тов в очереди

// поск пути по которому возможно пустить поток алгоритмом обхода графа в ширину

// функция ищет путь из истока в сток по которому еще можно пустить поток,

// считая вместимость ребера (i,j) равной c[i][j] - f[i][j],

// т.е. после каждой итерации(одна итерация - один поик пути) уменьшаем вместимости ребер,

// на величину пущеного потока

int FindPath(int source, int target) // source - исток, target - сток

{

QP = 0; QC = 1; Queue[0] = source;

Link[target] = -1; // особая метка для стока

int i;

int CurVertex;

memset(Flow, 0, sizeof(int)*NUM_VERTICES); // в начале из всех вершин кроме истока течет 0

Flow[source] = INFINITY; // а из истока может вытечь сколько угодно

while (Link[target] == -1 && QP < QC)

{

// смотрим какие вершины могут быть достигнуты из начала очереди

CurVertex = Queue[QP];

for (i=0; i<NUM_VERTICES; i++)

// проверяем можем ли мы пустить поток по ребру (CurVertex,i):

if ((c[CurVertex][i] - f[CurVertex][i])>0 && Flow[i] == 0)

{

// если можем, то добавляем i в конец очереди

Queue[QC] = i; QC++;

Link[i] = CurVertex; // указываем, что в i добрались из CurVertex

// и находим значение потока текущее через вершину i

if (c[CurVertex][i]-f[CurVertex][i] < Flow[CurVertex])

Flow[i] = c[CurVertex][i];

else

Flow[i] = Flow[CurVertex];

}

QP++;// прерходим к следующей в очереди вершине

}

// закончив поиск пути

if (Link[target] == -1) return 0; // мы или не находим путь и выходим

// или находим:

// тогда Flow[target] будет равен потоку который "дотек" по данному пути из истока в сток

// тогда изменяем значения массива f для данного пути на величину Flow[target]

CurVertex = target;

while (CurVertex != source) // путь из стока в исток мы восстанавливаем с помощбю массива Link

{

f[Link[CurVertex]][CurVertex] +=Flow[target];

CurVertex = Link[CurVertex];

}

return Flow[target]; // Возвращаем значение потока которое мы еще смогли "пустить" по графу

}

// основная функция поиска максимального потока

int MaxFlow(int source, int target) // source - исток, target - сток

{

// инициализируем переменные:

memset(f, 0, sizeof(int)*MAX_VERTICES*MAX_VERTICES); // по графу ничего не течет

int MaxFlow = 0; // начальное значение потока

int AddFlow;

do

{

// каждую итерацию ищем какй-либо простой путь из истока в сток

// и какой еще поток мажет быть пущен по этому пути

AddFlow = FindPath(source, target);

MaxFlow += AddFlow;

} while (AddFlow >0);// повторяем цикл пока поток увеличивается

return MaxFlow;

}

int main()

{

int source, target;

scanf("%d", &NUM_VERTICES);

scanf("%d %d", &source, &target);

int i, j;

for (i=0; i<NUM_VERTICES; i++)

for (j=0; j<NUM_VERTICES; j++)

scanf("%d",&c[i][j]);

printf("%d", MaxFlow(source, target));

return 0;

}

Транспортной сетью называется пара Т=(G,C) , где G - взвешенный орграф , удовлетворяющий следующим условиям:

а) нет петель;

б) существует только одна вершина, не имеющая ни одного прообраза - это исток;

в) существует только одна вершина , не имеющая ни одного образа - это сток;

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

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

Потоком в транспортной сети Т называется неотрицательная вещественная функция, определенная на множестве дуг, удовлетворяющая условиям:

  1. ограниченности: поток по любой дуге сети не превосходит пропускной способности этой дуги;

  2. сохранения: суммарный поток , заходящий в любую вершину сети ( кроме истока и стока ) равен суммарному потоку , выходящему из этой вершины.

Дуга сети называется насыщенной, если поток по этой дуге равен пропускной способности этой дуги.

Поток по пути называется полным, если хотя бы одна дуга пути насыщена.

Как упоминалось выше, поток в сети - это функция, определенная на множестве дуг. Величиной потока называется сумма значений этой функции по всем выходным дугам сети ( выходные дуги сети - это дуги, инцидентные стоку).Понятия потока и величины потока в сети часто путают, однако между ними существует различие: поток - это функция, а величина потока - число. Советуем это запомнить.

Разрезом сети называется множество , которому принадлежит исток, и не принадлежит сток. Т.е. разрез - это минимальное (в смысле отношения включения) множество дуг, удаление которых “ разрывает” все пути, соединяющие исток и сток.

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

Отыскание минимального разреза - одна из основных задач анализа транспортных сетей.

В силу конечности графа минимальный разрез может быть найден перебором всех разрезов, но этот путь, конечно, неприемлим для достаточно больших графов. Оказывается, что минимальный разрез можно отыскать при помощи максимального потока сети на основании теоремы Форда-Фалкерсона.

_________________________________________________________________

Теорема Форда-Фалкерсона.

В любой транспортной сети величина любого максимального потока

равна пропускной способности любого минимального разреза.

_________________________________________________________________

Известно конструктивное доказательство этой теоремы, на основании которого построен изложенный выше алгоритм.

Постановка задачи.

Найти максимальный поток в транспортной сети.

Алгорит Форда-Фалкерсона

1.Перенумеровать все вершины сети произвольным образом, кроме истока и стока. Пример.

2.Задать некоторый начальный поток в сети( например, нулевой). Пример.

3.Вершинам сети присвоить целочисленные метки, а дугам - знаки “+” и “-” по следующим правилам: а)вершине-истоку присвоить метку 0; Пример.

б)находим непомеченную вершину W , смежную помеченной вершине V. Если поток по соединяющей вершины V-W дуге меньше пропускной способности этой дуги, то происходит помечивание, иначе переходим к рассмотрению следующей вершины. Если вершина W является образом помеченной вершины V , то происходит прямое помечивание : вершина W получает метку ,равную номеру вершины V, соединяющая вершины V-W дуга получает метку “ + ” и мы переходим к рассмотрению следующей вершины. Если вершина W не имеет ни одного помеченного прообраза, то происходит обратное помечивание: вершина W получает метку, равную номеру вершины V ( являющейся в данном случае её образом ), соединяющая вершины W-V дуга получает метку “ - ” и мы переходим к рассмотрению следующей вершины.Процесс помечивания продолжается до тех пор , пока все удовлетворяющие этим условиям вершины не получат метку.Пример.

4. Если в результате процедуры помечивания вершина-сток метки не получила, то текущий поток - максимальный, задача решена. В противном случае, перейти к пункту 5.Пример.

5.Рассмотреть последовательность вершин L = ( U0, ... , v0) ,метка каждой из которых равна номеру следующей за ней вершины, и множество дуг М , соединяющих соседние вершины из L.Пример.

Построить новый поток по схеме:

Если дуга принадлежит множеству М( смотри выше ) и имеет знак “ + ”, то

новый поток по этой дуге = старый поток по этой дуге + К

  (схему нахождения К смотри ниже).

Если дуга принадлежит множеству М и имеет знак “ - ”, то

новый поток по этой дуге = старый поток по этой дуге - К

( схему нахождения К смотри ниже).

Если дуга не принадлежит множеству М ,то

новый поток по дуге = старый поток по этой дуге.

Схема нахождения К:

К = min{ К1;К2 }, где

Для нахождения К1 рассматриваются все дуги , принадлежащие множеству М и имеющие знак “ + ” и для каждой такой дуги вычисляется разность между пропускной способностью дуги и потоком по этой дуге. Затем из этих значений разностей выбирается минимальное значение и присваивается К1.

Для нахождения К2 рассматриваются все дуги , принадлежащие множеству М и имеющие знак “ - ” .Затем из этих дуг выбирается дуга с минимальным потоком и значение потока по этой дуге присваивается К2.

Перейти к п.3.

Алгоритм Форда-Фалкерсона используется при решении многих практических задач .Одна из них - Задача об источниках и потребителях.

Сети, потоки в сетях. Теорема Форда – Фалкерсона

Сетью называется связный граф (обычно, не орграф и не мультиграф), в котором заданы “пропускные способности” ребер, т. е. числа qij. Это числа большие или равные нулю, причем qij = 0 тогда и только тогда, когда нет ребра, соединяющего вершины i и j. Таким образом, можно считать, что пропускные способности ребер заданы для любой пары вершин. В дискретной математике пропускные способности ребер, как и все возникающие константы, считаются целыми числами (или рациональными, что одно и то же, так как рациональные числа отличаются от целых только единицами измерения). Заметим, что сети имеют огромные приложения, в частности, “сети планирования” (имеется в виду планирование производства некоторых новых, достаточно сложных изделий), где “пропускные способности” ребер – это время, за которое нужно из нескольких узлов изделия (вершин графа) получить другой (более сложный) узел. Сетевое планирование здесь не исследуется, так как гораздо больший интерес представляет сеть связи, где пропускные способности ребер – это обычно “количество одновременных разговоров”, которые могут происходить между телефонными узлами (вершинами графа).

Потоком в сети между вершиной t (источником) и s (стоком) называется набор чисел сij, (т. е. количество условного “груза”, перевозимого из вершины с номером i в вершину с номером j), удовлетворяющих четырем условиям:

1) числа сij  0, причем если сij > 0, то сji 0 (нет встречных перевозок);

2) числа cij   qij (соответствующих пропускных способностей ребер);

3) если вершина с номером i – промежуточная (не совпадает с источником и стоком), то

,

т. е. количество “груза”, вывозимого из вершины i, равно количеству “груза”, ввозимого в эту вершину;

4)  количество “груза”, вывозимого из источника t, должно быть равно количеству груза, ввозимого в сток s:

.

Число А называется величиной данного потока или просто потоком между t и s.

Для дальнейшего нам нужно следующее определение:

Пусть имеется некоторое сечение между вершинами t и s. Тогда величиной сечения называется сумма пропускных способностей ребер, входящих в это сечение. Сечение называется минимальным (максимальным), если его величина минимальна (максимальна).

Теорема Форда – Фалкерсона (1955). Максимальный поток между вершинами t и s равен величине минимального сечения между этими вершинами.

Доказательство этой теоремы является конструктивным (т. е. показывает, как найти нужный максимальный поток), поэтому приводится ниже.

  1. Докажем сначала, что любой поток между вершинами t и s меньше или равен величине любого сечения. Пусть дан некоторый поток и некоторое сечение. Величина данного потока складывается из величин “грузов”, перевозимых по всем возможным путям из вершины t в s. Каждый такой путь обязан иметь общее ребро с данным сечением. Так как по каждому ребру сечения суммарно нельзя перевести “груза” больше, чем его пропускная способность, поэтому сумма всех грузов меньше или равна, сумме всех пропускных способностей ребер данного сечения. Утверждение доказано.

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

  1. Докажем теперь обратное неравенство. Пусть имеется некоторый поток cij (какой-то поток всегда существует, например, нулевой, когда все cij = 0). Будем помечать вершины графа, причем считаем, что все помеченные вершины образуют множество Y. Пометки вершин производятся от источника. Каждая пометка вершины (если эта вершина может быть помечена) состоит из двух чисел: первое – это “+” или “–” номер вершины (из Y), c которой связана новая помечаемая вершина, и второе – (обязательно должно быть положительным) – это фактически та добавка к потоку, которая может быть дополнительно “довезена” в эту вершину из источника по сравнению с исходным потоком.

Более точно, множество помеченных вершин Y образуется следующим образом:

источник t принадлежит Y и его пометка (0, ); второе число, условно говоря, равно бесконечности – что для дискретной математики означает, что это настолько большое число, как нам понадобится;

если вершина i принадлежит Y и cij < qij (дуга (i,j) – прямая и ненасыщенная), то вершина j также принадлежит Y и пометка вершины j равна (+i, j), где j>0 равно j= min {i, qij – cij}. Заметим, что здесь число iэто второе число уже помеченной вершины i, а знак + перед номером i означает, что дуга, связывающая вершины (i, j) является прямой (и ненасыщенной);

если вершина к принадлежит Y и сjk > 0 (обратная дуга), то вершина с номером j также должна принадлежать Y и ее пометка равна (– к, j), где знак минус означает, что вершина j связана с уже помеченной вершиной к обратной дугой, j= min{k, qjk+cjk}, причем очевидно, что j также строго больше нуля. Таким образом, построение множества Y является индуктивным, т. е. новая вершина добавляется в Y, если она связана с некоторой вершиной уже входящей в Y либо прямой ненасыщенной дугой, либо обратной дугой.

После того как построение множества Y закончено (к нему нельзя добавить новых вершин), возможны 2 случая.

1. Сток (т. е. вершина с номером s) не входит в множество вершин Y. Тогда обозначим множество вершин, не входящих в Y через Z. Наш граф по условию является связным, поэтому из Y, в Z идут некоторые ребра. По правилам построения Y все эти ребра являются прямыми насыщенными дугами (рис. 7).

Ребра, идущие из множества Y в Z, образуют сечение между вершинами t и s. Видно также, что сумма пропускных способностей ребер этого сечения (а все эти ребра являются прямыми, насыщенными) равна потоку из t в s. Значит, данный поток является максимальным (так как он равен величине некоторого сечения), а данное сечение является минимальным.

2. Вершина s также входит в Y, и пусть второе число ее пометки  > 0. Тогда, очевидно, что между вершинами t и s существует цепь (состоящая из направленных ребер – прямых и обратных дуг), соединяющая эти вершины

Схематично это представлено на рис. 8.

ts

Рис. 8

Заметим, что дуга, выходящая из источника, и дуга, входящая в сток, должны быть обязательно прямыми. Прибавим  s к cij для прямых дуг этой цепи (по построению видно, что полученное число будет меньше или равно qij) и вычтем это  s из cij для обратных дуг (может получиться отрицательное число, но оно обязательно будет по абсолютной величине меньше qij, так как по построению  s  cij+qij , а это означает, что обратная дуга меняет направление, становится прямой дугой и его “нагрузка” будет равна модулю числа Тогда новые числа для дуг, входящих в нашу цепь, а также “старые” cij для всех дуг, не входящих в нашу цепь, образуют новый поток из вершины t в вершину s (легко проверить простым рассуждением, что для новых чисел выполняются условия (1)–(4)). Кроме того, величина нового потока по сравнению со старым увеличилась на s > 0  . Для нового потока снова проведем ту же процедуру и т. д.

Соседние файлы в папке Курсовая работа - Задача о максимальном потоке