Netwerkmodellen2

advertisement
Netwerkmodellen en Algoritmen
Netwerkmodellen
en algoritmen
Technisch Universiteit Delft
Docent:
Datum:
Dr. J.B.M. Melissen
20 juli 2017
1
Netwerkmodellen en Algoritmen
2
0 Inhoudsopgave
0
1
2
3
Inhoudsopgave
Inleiding
Netwerken
Netwerkmodellen
3.1
Terminologie
3.2
Transformaties
3.3
Niet-lineaire doelfuncties
4 Bomen
5 Algoritmes voor Max-Flow
5.1
Max-flow min-cut stelling
5.2
Algoritme van Ford en Fulkerson
5.3
Convergentieproblemen in Ford-Fulkerson
5.4
Algoritme van Karzanov
5.5
Toelaatbare stromen
6
7
Netwerkalgoritmen
Literatuur
2
3
3
6
6
7
10
11
12
12
13
16
17
19
23
24
Netwerkmodellen en Algoritmen
3
1 Inleiding
2 Netwerken
In dit hoofdstuk zullen we eerst een paar algemeenheden over netwerken herhalen. Een
netwerk of graaf is een paar (N, A), waarbij N een (eindige) verzameling van zogenaamde
knopen (hoekpunten, vertices, nodes, points, elements) is en A een deelverzameling van
NN. A is dus een verzameling van paren knopen die een verbinding tussen begin- en
eindknoop voorstellen en takken (zijden, arcs, edges, lines, branches) worden genoemd.
Een tak (a, b) heeft een beginknoop a en een eindknoop b en dus ook een richting. Als
richtingen in een graaf niet van belang zijn spreek je van een ongerichte graaf. Formeel kun
je dat doen door te eisen dat er voor elke tak ook een tak in tegengestelde richting loopt (de
verzameling A is symmetrisch), of door te zeggen dat de verzameling A een deelverzameling
is van de verzameling van deelverzamelingen van N die twee elementen bevatten. Een tak is
dan niet meer een geordend paar, maar een verzameling met twee elementen uit N (zonder
volgorde dus).
Een netwerk of graaf is in principe een abstract gegeven. Het is een verzameling van knopen
en een verzameling van paren knopen, de takken. Toch denken we vaak concreet over een
netwerk. De knopen tekenen we bijvoorbeeld als punten in het vlak en de takken zijn
verbindingslijntjes tussen de punten, eventueel voorzien van een pijlpunt om de richting aan
te geven.
Een bekend probleem dat met het tekenen van netwerken in het vlak te maken heeft is het
volgende: Je hebt een elektriciteitscentrale, een waterleidingbedrijf en een gasleverancier.
Drie huizen moeten elk van gas, water en licht worden voorzien. De vraag is nu of je elk huis
met elk van de leveranciers kunt verbinden zonder dat leidingen elkaar kruisen. Het
wiskundige probleem is: je neemt een volledige bipartite graaf K3,3 van drie punten op drie
punten (d.w.z. je tekent links drie punten en rechts ook. Elk van de punten links moet met elk
van de punten rechts worden verbonden). Is het mogelijk om deze graaf vlak te tekenen,
d.w.z. zonder doorsnijdingen van zijden? Als je dit gaat proberen zul je al snel merken dat
het telkens bijna lijkt te lukken, maar net niet helemaal. Dat komt omdat het niet kan.
Een bewijs dat het niet gaat kun je bijvoorbeeld halen uit een topologisch resultaat van Euler.
Als je in het vlak een vlakke graaf tekent en je telt het aantal knopen k, het aantal zijden z, en
het aantal gebiedjes v dat ontstaat (het buitengebied telt ook mee), dan geldt altijd: k – z + v =
2 (dit is eenvoudig met volledige inductie te bewijzen). Voor een n-hoek geldt bijvoorbeeld: n
- n + 2 = 2, voor een vierkant met zijn twee diagonalen geldt: 5 – 8 + 5 = 2.
Stel nu dat we K3,3 vlak kunnen tekenen, dan ontstaan er door doorsnijdingen geen nieuwe
knopen en zijden, dus k = 6 en z = 9. Dit betekent dat het aantal vlakjes v = 5 moet zijn. De
graaf kan circuits (cycles) bevatten, maar dat kunnen alleen vierhoeken of zeshoeken zijn,
omdat je alleen maar van een huis naar een voorziener kunt gaan of omgekeerd, maar
tussen de huizen onderling, of de voorzieners onderling is er geen verbinding. Het aantal
zijden is dus even, maar het aantal hoekpunten is maximaal 6. Stel dat je p vierhoeken hebt
en q zeshoeken, dan geldt: p + q = v = 5 (het aantal vlakjes), en 4p + 6q = 2z = 18 (elke zijde
wordt dubbel geteld). Deze twee vergelijkingen hebben als oplossing: p = 6, q = -1, dat kan
dus niet.
Hieronder zie je K3,3 met één zelfdoorsnijding k = 7 knopen, z = 11 takken en v = 5 vlakjes.
Netwerkmodellen en Algoritmen
4
Een precieze karakterisering van de grafen die vlak zijn geeft de volgende stelling:
Stelling (Kuratowski, 1922): Een graaf is vlak (zonder doorsnijdingen in het vlak te tekenen)
precies dan als K3,3 en K5 niet optreden als deelgraaf.
Hierin is K5 is de volledige graaf op 5 punten: Neem 5 punten en verbind elk punt met elk
ander punt.
De stelling van Kuratowski is niet van groot praktisch belang omdat het in de praktijk niet
meevalt om alle deelgrafen op 5 en 6 punten te onderzoeken. De beste bekende algoritmen
om de vlakheid van een graaf te onderzoeken hebben een complexiteit O(n).
Na dit negatieve resultaat is er ook een positief resultaat: Je kunt een willekeurige graaf wel
altijd in R3 “tekenen” zonder doorsnijdingen, en zelfs met rechte lijntjes:
Stelling Elke graaf is in te bedden in R3 waarbij de zijden (rechte) lijnstukken zijn die elkaar
alleen in knopen snijden.
Bewijs: We beelden de j-de knoop af op het punt (j, j2, j3) in R3. Het idee is dat de punten
dan zodanig “krom” in de ruimte liggen dat twee verschillende lijnstukjes elkaar hooguit in
eindpunten kunnen snijden. We nemen nu vier verschillende knopen met kentallen i, j, k en l
en we moeten laten zien dat het lijnstuk tussen de i-de en de j-de knoop niet het lijnstuk
tussen de k-de en de l-de knoop kan snijden. Dit betekent het voldoende is om te laten zien
dat de lijnstukken tussen i en j, tussen j en k en tussen k en l niet in één vlak liggen (want dat
is wel het geval als de twee lijnstukjes elkaar snijden), d.w.z. dat de vectoren
 i j   jk 
 k l 
 2
  2
 2 2

2
2
 i  j  ,  j  k  en  k  l 
 i3  j3   j3  k 3 
 k3  l3 

 



lineair onafhankelijk zijn. We moeten dus laten zien dat de determinant
i j
i j
2
jk
2
i3  j3
j k
k l
2
k2 l2
j3  k 3
k3  l3
2
ongelijk is aan 0. In deze determinant kun je per kolom factoren i-j, j-k en k-l buiten haakjes
halen:
Netwerkmodellen en Algoritmen
5
i j
jk
i2  j2
j2  k2
k 2  l 2 = (i  j )( j  k )( k  l )
i j
j k
k l
3
3
3
k l
3
3
1
1
i j
jk
i  ij  j
3
1
2
2
k l
j  jk  k
2
2
k  kl  l 2
2
Vegen met de eerste rij levert:
1
(i  j )( j  k )( k  l )
1
ik
i  ij  jk  k
2
(i  j )( j  k )( k  l )
1
l j
0
2
=
0 l  kl  jk  j
2
ik
l j
i  k i  j  k  l  j  j  k  l 
(i  j )( j  k )( k  l )(i  k )(l  j )
1
1
i j k j k l
(i  j )( j  k )( k  l )(i  k )(l  j )(l  i ) .
2
=
=
De determinant is ongelijk aan nul, omdat alle kentallen ongelijk aan elkaar zijn.

Netwerkmodellen en Algoritmen
6
3 Netwerkmodellen
3.1 Terminologie
Een bronknoop (source node) is een knoop waar alleen maar takken uit weggaan. Bij een
bronknoop hoort meestal een niet-negatief aanbod (supply) b > 0, de hoeveelheid stroom die
de bronknoop levert.
Een putknoop (sink node) is een knoop waar alleen maar takken in uitkomen. Bij een
putknoop hoort meestal een niet-positieve vraag (demand) b < 0, de hoeveelheid stroom die
de bronknoop nodig heeft
Een doorvoerknoop (transshipment node) is een knoop waar zowel takken in uitkomen als uit
weggaan. Een zuivere doorvoerknoop is een doorvoerknoop waar de vraag en het aanbod
gelijk is aan nul.
Een stroom is een toewijzing van niet-negatieve waarden aan de takken van het netwerk
zodanig dat er in elke knoop behoud van stroom is: alle stroom die de knoop in gaat moet er
ook weer uitkomen.
We bekijken in het algemeen stromingsproblemen (capacitated minimum cost flow problem),
waarbij de minimale stroming door een netwerk wordt gezocht, waarbij er op de takken
grenzen voor de stroom zijn aangegeven, en de knopen nog een externe vraag of aanbod
kunnen hebben. Een stromingsprobleem kan als volgt worden geformuleerd:
minimaliseer
c
ij
xij
i, j
onder voorwaarde dat
  xij   x ji  bi , voor elke knoop i.
j
j
lij  xij  u ij , voor elke zijde (i,j).
Hierin is xij de stroom tussen knoop i en knoop j. De coëfficiënten cij stellen de kosten (lineair
per eenheid) van een eenheidsstroom tussen knoop i en knoop j voor (als deze tak bestaat).
De bi stellen de waarden van de vraag (>0) of het aanbod (<0) voor. De lij en uij zijn de
onder- en bovengrenzen op de stroom per tak. De gegevens van een netwerkprobleem
kunnen grafisch in het netwerk worden uitgebeeld:
Een speciaal geval van een stromingsprobleem is een transportprobleem. Dit is een
stromingsprobleem zonder doorvoerknopen. elke knoop in het netwerk is dus een bronknoop
óf een putknoop. Tussen bronknopen onderling zijn er geen takken, want uit bronknopen
gaan alleen takken weg. Evenzo zijn er geen takken tussen putknopen. Je kunt alle
Netwerkmodellen en Algoritmen
7
bronknopen links zetten en alle putknopen rechts, dan ontstaat er een bipartite graaf: er zijn
alleen takken tussen de knopen links en de knopen rechts. Het transportprobleem modelleert
bijvoorbeeld het transport van goederen: Hoe kun je een gegeven aanbod het goedkoopst
naar afnemers met een bepaalde vraag brengen. Het is duidelijk dat een transportprobleem
alleen oplosbaar is als de totale vraag gelijk is aan het totale aanbod. Vanwege de
balansvergelijkingen – het behoud van stroom – kan er geen stroom verdwijnen of bijkomen.
Een eis voor de toelaatbaarheid van een transportprobleem is dus dat
bi  0 .

i
Een speciaal geval van een transportprobleem is het toewijzingsprobleem (assignment
problem). Dat is een transportprobleem waarin elk aanbod in een bronknoop 1 is en elke
vraag in een putknoop ook 1. Wil een toewijzingsprobleem toelaatbare oplossingen hebben,
dan moet het aantal bronknopen gelijk zijn aan het aantal putknopen. De stromen in het
netwerk zullen 0 of 1 zijn. Dat betekent dat elke bron aan precies één put wordt gekoppeld,
en dat op de goedkoopste manier, vandaar de naar “toewijzingsprobleem”.
Het kortste padprobleem kan ook worden geformuleerd als een netwerkprobleem. Het
startpunt wordt dan een bron met aanbod 1, de eindknoop een put met vraag 1. De kosten
van een zijde is zijn lengte. De minimale koststroming is dus een stroom ter grootte 1 die
langs de kortst mogelijke route van beginpunt naar eindpunt zal stromen.
3.2 Transformaties
We zullen nu een aantal transformaties bespreken waarmee netwerken kunnen worden
aangepast tot een equivalent netwerk.
1. Van een transportprobleem met geheeltallig aanbod en vraag kun je in principe een
(meestal zeer groot) toewijzingsprobleem maken. Dit kun je doen door elke bron- en
putknoop te splitsen in een aantal knopen dat gelijk is aan de betreffende aanbods- of
vraagwaarde van die knoop. De gesplitste knopen krijgen allemaal een bron-/putwaarde
gelijk aan 1. De takken lopen hetzelfde als bij de moederknopen, de kostencoëfficiënten
blijven ook gelijk. Voorbeeld:
Deze constructie geeft alleen aan dat een geheeltallig transportprobleem equivalent is met
een toewijzingsprobleem, maar enig praktisch nut is er niet, omdat het toewijzingsprobleem
Netwerkmodellen en Algoritmen
8
in het algemeen erg groot is, en de grootte niet alleen afhangt van het oorspronkelijke
netwerk van het transportprobleem, maar ook van de grootte van de vraag en aanbod.
2. Elke zuivere doorvoerknoop kan worden gesplitst in een bron- en een putknoop:
Door het splitsen krijgen we twee knopen, waarbij de bronknoop Vs alle takken krijgt die de
originele knoop uitgingen (want een bronknoop kan alleen uitgaande takken hebben), terwijl
alle takken die erin kwamen naar de putknoop Vd gaan. Een verbinding tussen de nieuwe
bron- en putknoop kan dus automatisch alleen van bron naar put lopen. Verder geven we de
bronknoop een aanbod ter grootte M1 en de putknoop een vraag ter grootte M2, waarvan we
de waarde nog even niet vastleggen. De tak tussen Vs en Vd krijgt een kostencoëfficiënt 0,
zodat de extra tak geen invloed heeft op de doelfunctie.
Als we de twee nieuwe balansvergelijkingen, die naast de nieuwe knopen staan, bij elkaar
optellen zien we dat
 M 2  M1 
xVi  x jV  0 ,


i
j
vanwege de balansvergelijking in de originele knoop. Hieruit volgt dat M1 = M2 =: M.
Verder moet voor de stroom tussen Vs en Vd gelden dat 0  x sd  M 
xVi . Dit betekent

i
dat M groter moet zijn dan de stroom die maximaal door V kan stromen (bijvoorbeeld de som
van de capaciteiten van de inkomende takken).
Het splitsen van een knoop is ook uit te voeren als er in de originele knoop een extra vraag
of aanbod is.
3. Een tak met grenzen kan worden vervangen door het invoegen van een extra knoop en
takken zonder grenzen:
Netwerkmodellen en Algoritmen
9
In het originele netwerk gelden de volgende twee balansvergelijkingen in de knopen:
xVi  x jV  xVW  0 ,


i
j
x
Wk
 xlW  xVW  0 .
k
l
In het nieuwe netwerk hebben we drie knopen en dus ook drie balansvergelijkingen:
xVi  x jV  xVI  a ,


i
j
 xVI  xW I  b  a  ,
x
Wk
k
 xW  xW I  b .
l
De eerste balansvergelijking in het nieuwe netwerk zegt dat de stroom die uit V richting I en
dus W loopt gelijk is aan xVi + a. De derde balansvergelijking in het nieuwe netwerk zegt dat
de stroom die in W komt vanuit de richting I en dus vanuit W gelijk is aan –xWi + b. De
middelste balansvergelijking zegt dat deze twee stromen gelijk zijn. Dat moet ook, want ze
moeten gelijk zijn aan xVW uit het originele netwerk. We hebben nu dus dat
xVW = xVI + a = –xWI + b.
Omdat de stromen xVI en xWI in het nieuwe netwerk niet-negatief zijn volgt uit deze
representatie automatisch dat a  xVW  b, zonder dat er expliciete capaciteitsgrenzen zijn
gegeven in het nieuwe model.
De bijdrage aan de doelfunctie is in het tweede netwerk: cxVI + ca = cxVW, dus ook dat klopt.
De speciale gevallen a = 0 (geen ondergrens) en b =  (geen bovengrens) staan hieronder.
Netwerkmodellen en Algoritmen
10
3.3 Niet-lineaire doelfuncties
De hele theorie van netwerkmodellen is erop gebaseerd dat de doelfunctie lineair is. De
kostencoëfficiënt van elke tak geeft de kosten van een stroom door die tak per eenheid. Toch
kun je ook een beperkte vorm van niet-lineariteit in het model stoppen door middel van
meerdere takken tussen dezelfde knopen met capaciteitsgrenzen en verschillende
kostencoëfficiënten.
Maak bijvoorbeeld tussen twee knopen twee takken in dezelfde richting, één met
kostencoëfficiënt 2 en begrenzend interval [0,10], en de tweede met coëfficiënt 3 en interval
[0,5]. Dit levert een verbinding op tussen de twee knopen met een begrenzend interval [0,15]
en een niet-lineaire kostenfunctie op de tak. als de stroom tussen 0 en 10 ligt zal deze
stroom volledig door de eerste tak gaan, omdat daarvan de kosten het laagst zijn. De
richtingscoëfficiënt van de doelfunctie is daar 2. Pas als de stroom groter wordt dan 10 gaat
alles wat boven de 10 uitkomt door de tweede tak, omdat dat het eerstvolgend goedkoopste
alternatief is. De richtingscoëfficiënt van de doelfunctie is daar 3. Voor een stroom x van de
eerste naar de tweede knoop hebben we dus de volgende kostenfunctie:
c(x) = 2x,
c(x) = 3x –10
0  x  10
10  x  15
De term -10 komt van de continuïteit van de kostenfunctie.
Als we ook nog een tak van de tweede naar de eerste knoop terug opnemen met
kostencoëfficiënt 5 en interval [0,7], dan krijgen we de volgende kostenfunctie:
c(x) = -5x,
c(x) = 2x,
c(x) = 3x –10
-7  x  0
0  x  10
10  x  15
In het algemeen kun je zo op een tak een stuksgewijs lineaire kostenfunctie maken door elk
lineair interval met een extra tak te associëren. Omdat de kosten door de tak
geminimaliseerd worden is er echter wel de restrictie dat de richtingscoëfficiënten niet dalend
zijn, m.a.w. de stuksgewijs lineaire functie moet convex zijn (de grafiek is hol naar boven).
Netwerkmodellen en Algoritmen
11
4 Bomen
Een belangrijke klasse van netwerken wordt gevormd door de bomen. Dat zijn netwerken
met een “minimaal” aantal verbindingen tussen knopen. Een boom is een goedkope manier
om knopen met elkaar te verbinden, omdat er geen overbodige verbindingen in voorkomen,
er is tussen elk paar knopen maar één mogelijke verbinding. Een boom definiëren we dus als
een netwerk zonder circuits (cycles, loops). Een boom heet leeg als er geen takken in
voorkomen. Een lege boom kan dus wel knopen bevatten! De graad van een knoop is het
aantal takken dat die knoop als begin- of eindpunt heeft.
Lemma 1: Elke niet-lege boom heeft een knoop met graad gelijk aan 1.
Bewijs: Stel dat we een niet-lege boom hebben zonder knopen van graad 1. De graad van
een willekeurige knoop is dus gelijk aan 0, of is minstens twee. Omdat de boom niet leeg is,
is er een tak. Het eindpunt van die tak heeft niet graad 0, dus minstens 2. Er is dus nog een
andere tak die in dat punt begint of eindigt. Volg die tak naar zijn andere knoop. Dit is weer
een knoop met graad minstens 2. Zo kun je doorgaan en elke keer weer een knoop vinden.
Omdat het totale aantal knopen eindig is, moet je op een gegeven moment op een punt
terecht komen dat je al eerder hebt bezocht. Dat kan echter niet omdat je dan een circuit zou
hebben gevonden, maar die zijn er niet in de boom. Dit is een tegenspraak: er is dus wél een
knoop met graad 1.

Een niet-lege boom blijkt zelfs altijd twee punten met graad 1 te hebben:
Lemma 2: Elke niet-lege boom heeft twee knopen waarvan de graad gelijk is aan 1.
Bewijs: Volgens Lemma 1 is er een punt met graad 1. Stel nu weer dat er verder geen
punten met graad 1 zijn. Je kunt dan vanuit het eerste punt weer een pad maken dat zichzelf
moet snijden. Dat levert een tegenspraak op.

Het is duidelijk dat we deze tendens niet kunnen generaliseren. Een pad tussen n knopen
bevat maar twee punten van graad 1, namelijk het begin- en het eindpunt. De andere n-2
punten hebben graad 2.
Stelling: Een samenhangend netwerk bevat geen circuits dan en slechts dan als het aantal
knopen gelijk is aan het aantal zijden plus 1.
Bewijs: “”. We nemen eerst aan dat we een samenhangend netwerk hebben zonder
circuits en gaan met inductie bewijzen dat het aantal knopen gelijk is aan het aantal zijden
plus 1. Als er maar één knoop is, is het duidelijk dat het aantal zijden gelijk is aan 0, dus dat
klopt. Stel nu dat de uitspraak klopt voor netwerken met n knopen en stel dat we een
samenhangend netwerk zonder circuits hebben met n+1 knopen. Volgens Lemma 1 is er een
knoop met graad 1. Laat deze knoop met zijn verbindende tak even weg en je houdt een
samenhangend netwerk over met n knopen. Er zijn dan dus n-1 takken. Voeg nu de knoop
en de tak toe en je hebt n = (n+1) –1 takken.
We bekijken nu een belangrijk soort boom, namelijk de opspannende boom van een
netwerk. Dat is een boom die je krijgt door in een netwerk zoveel mogelijk takken weg te
laten, maar wel zodanig dat alle knopen die verbonden waren ook verbonden blijven.
“Opspannend” betekent dat alle knopen van het netwerk ook knopen zijn van de
opspannende boom en aan de boom verbonden zijn. Voor een (ongericht) netwerk met n
knopen definiëren we een opspannende boom als een deel-netwerk dat n-1 takken heeft.
Netwerkmodellen en Algoritmen
12
5 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.
5.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
13
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.
5.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
14
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
15
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
16
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
5.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
17
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.
5.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
18
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
19
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.
5.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
20
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
21
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
22
Netwerkmodellen en Algoritmen
23
6 Netwerkalgoritmen
In het voorgaande hebben we veel moeite gedaan om optimaliseringsproblemen te
formuleren als een netwerkprogrammeringsprobleem (kortweg NP). Een reden daarvoor is
dat er voor netwerkproblemen snellere algoritmen zijn dan voor gewone LP problemen. We
zullen hier een aantal algoritmen bespreken aan de hand van het volgende NP probleem:
Uitgeschreven als LP-probleem ziet het er als volgt uit:
min {cTx | Ax = d, a  x  b}.
Netwerkmodellen en Algoritmen
24
7 Literatuur
C. Roos, Netwerkmodellen en algoritmen, dictaat TU Delft, 1991.
H.A. Eiselt and C.-L. Sandblom, Integer Programming and Network Models, Springer, 2000,
F. Glover, D. Klingman, and N.V. Phillips, Network Models in Optimization and their Applications in Practice. Wiley, 1992.
Download