karzanov

advertisement
Netwerkmodellen en Algoritmen
1
0 Algoritmes voor Max-Flow
Een belangrijk type netwerkprobleem is het maximale stroomprobleem (Max-Flow problem).
Het probleem bestaat uit het vinden van een zo groot mogelijke stroom door een netwerk
van een gegeven beginknoop naar een gegeven eindknoop, waarbij capaciteiten
(bovengrenzen voor de stroom) op de takken zijn vastgelegd.
Het netwerkje hierboven is daar een simpel voorbeeldje van. Je kunt er 9 eenheden
doorheen laten stromen: 5 via n1 en 4 via n2. We zullen hier twee algoritmes behandelen
waarmee in het algemeen zo’n maximale stroom kan worden bepaald.
0.1 Max-flow min-cut stelling
Als je naar een netwerk kijkt, waarin een maximale stroom wordt gezocht, kun je vaak op
voorhand al uitspraken doen over de mogelijke waarden van een stroom door het netwerk.
Als je bijvoorbeeld de capaciteiten optelt van alle takken die van de beginknoop uitgaan geeft
dit een bovengrens voor de stroom die door het netwerk kan lopen, want alle stroom moet
vanuit de beginknoop het netwerk in. In het bovenstaande voorbeeldje levert dat 5 + 7 = 12.
Evenzo is de som van de capaciteiten van alle takken die in de eindknoop uitkomen ook een
bovengrens. In het voorbeeld: 7 + 4 = 11. De kleinste van de twee waarden die we zo vinden
is weer een bovengrens voor de stroom. (In het voorbeeld is dit 11).
Wat algemener kunnen we ook een “muurtje” maken dat het netwerk doorsnijdt, zodanig dat
de in- en de uitgang van het netwerk aan verschillende kanten van het muurtje liggen. Alle
stroom moet van de ingang naar de uitgang en moet de muur passeren. Als je dus de totale
capaciteit neemt van alle takken die door het muurtje heen gaan krijg je een bovengrens
voor de stroom door het netwerk. Bij het optellen van de capaciteiten moet je opletten dat je
alleen de takken telt die de muur in de goede richting snijden, van ingang naar uitgang, want
alleen die takken kunnen een positieve bijdrage leveren aan de totale stroom. De takken die
terug lopen kunnen de totale stroom alleen verkleinen. Hun grootste positieve bijdrage is 0.
Netwerkmodellen en Algoritmen
2
Een muurtje dat het netwerk in tweeën deelt, met de in- en uitgang elk aan verschillende
kanten heet ook wel een snede (cut). Wat formeler geformuleerd is een snede een partitie
(verdeling) van alle knopen in twee verzamelingen, waarbij de in- en uitgangsknoop in
verschillende verzamelingen zitten. Voor een netwerk met n knopen zijn er dus 2n-2
verschillende sneden mogelijk, als je de ingangsknoop in de eerste verzameling doet en de
uitgangsknoop in de tweede. Elke andere knoop kun je namelijk telkens in de eerste óf in de
tweede verzameling stoppen.
Bij elke snede hoort een bovengrens voor de stroom die je vindt door de capaciteiten van de
(doorsneden) takken van verzameling 1 naar verzameling 2 op te tellen. Het minimum van
deze bovengrenzen over alle mogelijk sneden blijkt een scherpe bovengrens te zijn voor de
totale stroom door het netwerk, d.w.z., er is een stroom te vinden die deze bovengrens
aanneemt. Dit is de inhoud van de
Max-flow min-cut stelling: Er is een stroom (max-flow) in het netwerk die de waarde van de
kleinste capaciteitsgrens over alle snedes (min-cut) aanneemt.
Voorbeeld: In het simpele netwerk van hierboven zijn vier mogelijke sneden. Dit levert de
volgende bovengrenzen op:
5+7 = 12,
7+2+7 = 16,
5+4 = 9,
7+4 = 11.
De kleinste bovengrens is 9 en er is inderdaad een stroom 9 door het netwerk mogelijk: 5
eenheden door de bovenste twee takken en 4 door de onderste twee.
0.2 Algoritme van Ford en Fulkerson
Hoe kun je nu een maximale stroming door een netwerk bepalen? Een voor de hand liggend
idee is het volgende: Je zoekt in het netwerk een pad van begin- naar eindpunt, kijkt hoeveel
er langs dit pad kan (het minimum van de capaciteiten langs dit pad) en laat dit er vervolgens
doorheen lopen. Je kunt alle capaciteiten langs het pad dan met het bedrag van de stroom
verlagen. Vervolgens zoek je weer een ander pad, etc. Dit kun je doen totdat er geen pad
meer mogelijk is waarlangs nog stroom kan lopen. Heb je dan de maximale stroom
gevonden? Het antwoord is helaas: Nee! Kijk maar naar het volgende voorbeeld:
Netwerkmodellen en Algoritmen
3
Kies als eerste pad: ns  n1  n2  nt. Langs dit pad kan maximaal 2 stromen. Kies
vervolgens: ns  n1  nt. Hierlangs kan nog 3 stromen. Tenslotte kun je langs ns  n2  nt
nog 2 eenheden laten stromen. Nu lijkt het netwerk verzadigd. Vanuit s kan er niets meer
naar n1, die stroom is al maximaal. Er kan nog wel iets naar n2, maar dat kan niet naar nt
omdat de stroom van n2 naar nt al maximaal is en de pijl van n2 naar n1 de verkeerde kant op
staat. We hebben nu een totale stroom van 7 gevonden, maar die is niet maximaal. We
zagen namelijk eerder dat de minimale snede van dit netwerk 9 oplevert en dat je inderdaad
een stroom 9 kunt realiseren door 5 eenheden langs n1 te sturen en 4 eenheden langs n2.
Waarom werkt dit algoritme niet? Dat komt omdat we door de keuze van het eerste pad twee
eenheden die over n1 kwamen de verkeerde kant uit hebben gestuurd, via n2, en daardoor
capaciteit van de tak n2  nt hebben opgesnoept, die beter gebruikt had kunnen worden voor
de stroom over ns  n2  nt. Ook kun je zeggen dat we onszelf gefopt hebben door te
denken dat er vanuit n2 geen stroom naar n1 kan lopen omdat de pijl de verkeerde kant
opstaat. Je kunt namelijk wél een stroom ter grootte 2 van n2 naar n1 laten lopen, omdat er al
een stroom van n1 naar n2 liep. Die twee eenheden kun je terugnemen, waarmee je feitelijk
een extra stroom van n2 naar n1 hebt laten lopen. Effectief komt het er op neer dat er dan
geen stroom meer loopt van n1 naar n2, je hebt de eerder ingestelde stroom in tweede
instantie teruggenomen. Dat betekent dat het mogelijk is om nog een stroom ter grootte 2 te
laten lopen over ns  n2  n1  nt. Dit brengt de stroom in totaal op 9, en dat is wel
maximaal.
Om duidelijker te maken hoe het zit met het “terugnemen” van stroom kun je het beter
hebben over de residuele graaf (residual graph) die hoort bij een stroom in de graaf. In deze
graaf wordt elke gerichte tak in het originele netwerk vervangen door twee takken met
tegengestelde richtingen met elk een capaciteit. De capaciteiten geven aan hoeveel er
maximaal nog in die richting kan stromen. Een tak met een capaciteit van 5 waardoor
momenteel 3 eenheden stromen wordt dus vervangen door een tak met capaciteit 2 en een
tak terug met capaciteit 3. Als er nog niets doorheen stroomt blijft het een tak met capaciteit
5 (de tak terug heeft capaciteit 0), en als er een maximale stroom doorheen gaat is er alleen
een tak terug met capaciteit 5 (de tak heen heeft capaciteit 0). Ter illustratie volgen hieronder
Netwerkmodellen en Algoritmen
4
de verschillende residuele grafen als gevolg van de drie stappen die we eerder hebben
beschreven.
Je ziet aan de laatste residuele graaf onmiddellijk dat er nog 2 eenheden over het pad s  2
 1  t kunnen stromen. Dit levert de volgende residuele graaf:
In deze graaf is er geen stroom meer mogelijk van s naar t. Dat betekent dat het algoritme
hier stopt. We hebben nu een stroom van in totaal 9 eenheden gevonden van s naar t en dat
is maximaal. De oplossing die we nu gevonden hebben is:
De oplossing krijg je door de capaciteiten van de takken uit de residuele graaf te nemen die
tegengesteld lopen aan takken uit de originele graaf en deze waarden als stroom bij de
bijbehorende tak in de originele graaf te nemen.
Het algoritme dat we nu aan de hand van een voorbeeld hebben beschreven is het algoritme
van Ford en Fulkerson (1956):
Start met een toelaatbare stroom (meestal stroom 0 op alle takken).
while er is nog een pad waar een stroom kan lopen do
Kies een pad waarlangs nog een stroom kan lopen.
Laat de maximale stroom langs dit pad lopen.
Pas de residuele graaf aan.
Netwerkmodellen en Algoritmen
5
od
Een illustratie met behulp van Java applets is bijvoorbeeld te vinden op
http://www-b2.is.tokushima-u.ac.jp/~ikeda/suuri/maxflow/Maxflow.shtml
0.3 Convergentieproblemen in Ford-Fulkerson
Het algoritme van Ford-Fulkerson is zeer geschikt om met de hand kleine voorbeeldjes op te
lossen. Uiteindelijk is het natuurlijk bedoeld om grotere problemen op een computer aan te
pakken. Dat betekent dat de stap “zoek een pad van begin- naar eindpunt” ook
geautomatiseerd moet worden. In principe levert dat een zoektocht op via knopen over
takken, waarbij met backtracking een geschikt pad moet worden gevonden. Hoewel het
algoritme in de praktijk best goed voldoet zijn er toch een aantal problemen. De eindigheid
van het algoritme is duidelijk als alle capaciteiten geheeltallig zijn. Bij elke stap in het proces
treedt namelijk een verbetering op en wordt de totale stroom een geheel aantal eenheden
groter. Omdat de kleinste snede en dus de maximale stroom ook geheeltallig is, bereikt het
algoritme deze waarde in een eindig aantal stappen. Dit argument werkt niet als de
capaciteiten geen rationale verhoudingen hebben. Het algoritme hoeft dan ook niet eindig te
zijn. Wel convergeert het proces natuurlijk, omdat de stroom na elke iteratie groter wordt en
er een bovengrens is. Helaas hoeft deze limietstroom niet de maximale stroom in het
netwerk te zijn.
Een ander probleem is, dat er bij veel strategieën om tot een mogelijke stroom van beginnaar eindpunt te komen voorbeelden te verzinnen zijn waarvoor het Ford-Fulkerson
algoritme erg veel stappen doet voor het vinden van de beste oplossing. Als voorbeeld
bekijken we het onderstaande netwerk.
Als strategie om een toelaatbaar pad te bepalen kiezen we backtracking, waarbij om de
andere iteratie eerst de knopen met de laagste, resp. hoogste index worden afgezocht. De
capaciteiten op de takken zijn allemaal M, een erg groot getal, behalve op de tak 3  4, daar
is de capaciteit 1. Je ziet eenvoudig de beste oplossing voor dit probleem: Er moet een
stroom M door de bovenste takken lopen en ook een stroom M door de onderste takken. Dat
deze stroom van 2M maximaal is zie je met behulp van een snede.
Het algoritme van Ford-Fulkerson doet met de gekozen strategie het volgende. Eerst wordt
een toelaatbaar pad gezocht met minimale indices. Dat betekent dat er vanuit 1 wordt
gekozen voor 1, vervolgens voor 3 (ligt vast), dan voor 4, vervolgens voor 2 en dan naar t.
Over het pad ns  n1  n3  n4  n2  t kan maximaal 1 eenheid lopen. De tweede iteratie
kiest de hoogste indices en levert het pad ns  n6  n4  n3  n5  nt. Ook over dit pad kan
1 eenheid stromen. Het is duidelijk wat er gebeurt: Bij elke iteratie wordt de stroom met 1
eenheid verhoogd. Dit betekent dat het 2M iteraties duurt voordat je de maximale stroom
hebt gevonden. Dat staat in schril contrast met de twee iteraties die nodig zijn als je de
paden geschikt kiest.
Netwerkmodellen en Algoritmen
6
Om deze convergentieproblemen te vermijden werd door Edmonds en Karp (1972)
voorgesteld om altijd het pad met de grootst mogelijk stroom op te zoeken, in plaats van de
eerste de beste. Dit brengt natuurlijk wel meer rekenwerk met zich mee. Later (Gabow 1985
en Ahuja/Orlin, 1991) werd aangetoond dat het niet noodzakelijk is om de grootst mogelijke
stroom op te zoeken, als de stroom maar “groot genoeg” is in een of andere zin. Het
rekenwerk voor het zoeken van een geschikt pad wordt hierdoor minder. Voor gehele
capaciteitsgrenzen op het netwerk is de rekentijd van de orde O(n4log U), waarbij n het
aantal knopen is en U de grootste capaciteitsgrens in het netwerk.
0.4 Algoritme van Karzanov
Het idee van het algoritme van Karzanov is dat je, in plaats van één pad per keer te
gebruiken, zoals bij Ford-Fulkerson, ook de stroom op meer paden tegelijk kunt aanpassen.
We zullen het algoritme bekijken aan de hand van een simpel voorbeeld:
De minimale snede van dit netwerk ligt om knoop nt, en heeft een waarde van 3 + 5 =8. Er is
ook eenvoudig een maximale stroom 8 te maken.
Een iteratie uit het algoritme van Karzanov bestaat telkens uit de volgende drie stappen:
1. Maak een zogenaamd gelaagd netwerk. Dat zijn een aantal paden die van beginpunt
naar eindpunt lopen en waarover de stroom nog kan worden aangevuld. Dit werkt als
volgt: Eerst verdeel je het netwerk in lagen. Laag 0 bevat de beginknoop. Laag k
bevat de knopen die via k takken van het residuele netwerk (takken waarover nog
stroom kan lopen) verbonden zijn met de beginknoop. Uit het residuele netwerk
worden alle takken weggelaten die niet naar een volgende laag lopen, en ten slotte
worden alle takken en knopen weggelaten die niet op een pad van begin- naar
eindpunt liggen.
2. “Advance”: Loop de paden van begin- naar eindpunt af en laat er per tak de
maximale hoeveelheid stroom doorlopen. Alles wat er in een knoop komt mag door,
tenzij het beperkt wordt door de capaciteit van de uitgaande tak. Er is soms een
vrijheid hoe je de stroom over de uitgaande takken verdeelt. Er ontstaat een
zogenaamde “preflow”. Dat is nog geen gewone stroom, omdat er in de knopen geen
balans hoeft te zijn. Er kan meer ingaan dan er uitkomt. Dat is ook meteen de
definitie van een preflow: Een toewijzing van stroomwaarden aan de takken zodanig
dat in elke knoop minstens evenveel stroom gaat als er uit komt. Hierin kan ook
keuzevrijheid zijn.
3. “Balance”. Om van deze preflow een echte stroom te maken, worden vanuit het
eindpunt naar het beginpunt alle knopen gebalanceerd: de stroom op de ingaande
tak wordt zodanig gereduceerd dat er balans in de knoop ontstaat.
Netwerkmodellen en Algoritmen
7
In het voorbeeld van hierboven werkt dit als volgt. Eerst geef je de lagen aan en laat je alle
overbodige takken weg. In ons geval verdwijnt tak n1  n2, omdat die in laag 1 blijft:
Vervolgens laten we grootst mogelijke preflow door dit netwerk lopen (a):
Door de tak ns  n1 loopt een stroom ter grootte van de capaciteitsgrens: 6. Door de
capaciteitsgrens 3 op tak n1  nt blijft er op deze tak van de ingaande stroom 6 maar 3 over.
Dit levert een preflow. De stroom is in n1 niet gebalanceerd.
Vervolgens moet het netwerk gebalanceerd worden (b). Dit betekent dat de stroom op ns 
n1 moet worden gereduceerd tot 3, om knoop n1 in balans te krijgen. De andere knopen zijn
al in balans. We hebben nu van de preflow een stroom gemaakt en deze stroom is het
resultaat van de eerste iteratie.
We maken nu de gereduceerde graaf van deze stroom (a):
Netwerkmodellen en Algoritmen
8
Er zijn in dit gereduceerde netwerk 4 lagen. Vervolgens laten we weer alle takken weg die
niet naar een volgende laag lopen en krijgen het netwerk (b). De preflow die hierbij hoort is
hieronder te zien (a)
Door de preflow te balanceren ontstaat een stroom (zie (b) hierboven).
In het gereduceerde netwerk dat ontstaat (hieronder (b)) zie je dat er nu geen pad meer is
met een stroom van begin- naar eindpunt.
De oplossing die door het algoritme is gevonden staat in (a).
Bij een goede implementatie heeft het algoritme van Karzanov een complexiteit van O(n3).
De meeste state-of-the-art algoritmes zijn tegenwoordig gebaseerd op het concept preflow.
0.5 Toelaatbare stromen
De algoritmes die we hebben bekeken voor Max-Flow zijn gebaseerd op het successievelijk
verbeteren van een bestaande stroming. Dat is geen probleem als er op de takken alleen
maar bovengrenzen zijn gegeven voor de stromen. We kunnen dan altijd starten met de
nulstroom, een stroom 0 op alle takken. Dat is een toelaatbare stroom en tijdens het
algoritme wordt ervoor gezorgd dat de stroom toelaatbaar blijft. Als er ook ondergrenzen
voor de stromen gegeven zijn zitten we met een probleem, want er moet dan eerst een
toelaatbare stroom worden gevonden. Dat kan wel eens tegenvallen voor een groot netwerk.
We zullen nu zien hoe je een toelaatbare stroom kunt vinden.
Als xij de stroom van knoop i naar knoop j is, dan gelden er in het algemeen boven- en
ondergrenzen voor deze stroom:
lij  xij  uij
Verder moet in elke knoop i de balansvergelijking gelden:
Netwerkmodellen en Algoritmen
x x
ij
j
ji
9
0
j
Als er geen ondergrenzen zijn: lij = 0, dan is de nulstroom xij = 0 (voor alle i en j) toelaatbaar.
Als dat niet zo is halen we de volgende truc uit: We definiëren nieuwe variabelen
xij’ = xij - lij
Het effect van dit verschuiven van de variabelen is dat de ondergrenzen verdwijnen maar dat
in de knopen kunstmatige bronnen en putten ontstaan:
x
j
ij
'   x ji '   l ji   lij : bi
j
j
j
0  xij’  uij - lij
Dit is niet meer dan een herverdeling, want alle bronnen en putten die zo ontstaan heffen
elkaar in totaal gezien op.
Het idee is nu dat we deze artificiële tekorten en overschotten gaan koppelen aan een
superbron ns* en een superput nt*, die we als twee extra knopen aan het originele netwerk
zullen toevoegen.
Als bi > 0 dan wordt ni verbonden met ns*, met capaciteit bi.
Als bi < 0 dan wordt ni verbonden met nT*, met capaciteit -bi.
De oorspronkelijke takken uit het netwerk krijgen als capaciteit uij - lij.
Als voorbeeld bekijken we het volgende netwerk, waar bij elke tak de ondergrens en de
bovengrens voor de stroom staat aangegeven.
De tak van eind- naar beginknoop geeft aan dat we een maximale stroom zoeken. De
capaciteit M heeft een grote waarde, groter dan de totale stroom kan zijn (bijvoorbeeld de
waarde van een snede). Door de ondergrenzen is een stroom 0 op alle takken niet
toelaatbaar. De balansvergelijkingen in dit netwerk zijn:
Knoop ns:
– xts + xs1 + xs2 = 0.
Knoop n1:
– xs1 + x1t + x12 = 0.
Knoop n2:
– xs2 – x12 + x2t = 0.
Knoop nt:
– x1t – x2t + xts = 0.
Nu gaan we over op nieuwe variabelen :
xts = xts’.
xs1 = xs1’ + 1.
xs2 = xs2’ + 1.
x1t = x1t’.
x12 = x12’ + 2.
x2t = x2t’ + 2.
Met deze nieuwe variabelen krijgen we de volgende balansvergelijkingen :
Knoop ns:
– xts’ + xs1’ + xs2’ = – 2 = bs.
Knoop n1:
– xs1’ + x1t’ + x12’ = – 1 = b1.
Netwerkmodellen en Algoritmen
10
Knoop n2:
– xs2’ – x12’ + x2t’ = 1 = b2.
Knoop nt:
– x1t’ – x2t’ + xts’ = 2 = bt.
Het uitgebreide netwerk met de superbron en de superknoop ziet er nu als volgt uit :
In dit netwerk moeten we een toelaatbare stroom vinden, met de kanttekening dat de
superknoop 3 eenheden moet leveren en de superput 3 eenheden moet afvoeren. We gaan
nu wegen van de superbron naar de superput zoeken waar stroom doorheen kan. Als eerste
pakken we ns*  nt  ns  n1  nt*. Over dit pad kan 1 eenheid stromen. Het pad ns*  n2 
nt  ns  nt* is ook goed voor 1 eenheid. Ten slotte kan er nog 1 eenheid langs ns*  nt  ns
 nt*. De drie paden staan getekend in de volgende figuur:
Hiermee hebben we een stroom gevonden die aan alle grenzen voldoet. Vervolgens
schrijven we op wat dit voor het oorspronkelijke netwerk betekent. Hierbij moet worden
gecorrigeerd voor de verschuivingen die we in de stromen hebben geïntroduceerd door over
te gaan op nieuwe variabelen:
Een toelaatbare stroom in het netwerk die we zo hebben geconstrueerd is te zien in het
volgende plaatje:
Netwerkmodellen en Algoritmen
11
Download