Avanserte flytalgoritmer Magnus Lie Hetland, mars 2008 Stoff hentet fra: Network Flows av Ahua m.fl. (Prentice-Hall, 1993) Graphs, Networks and Algorithms, 2. utg., av Jungnickel (Springer, 2005) Repetisjon og eksempler, flyt og sirkulasjon Intro: Grunnleggende definisjon av flyt og sirkulasjon. (Algdat-stoff.) Maks-flyt: Nettverk med kapasiteter; finn maksimal flyt fra s til t der flyt i hver kant kant er under kapasiteten og flyt inn i en node er lik flyten ut (bortsett fra for s og t). Sirkulasjon: Ingen spesiell s og t; kanter har kostnader og både øvre og nedre kapasitet. Finn billigste sirkulasjon en tilordning av «flyt» til hver kant med samme beskrankninger, med laveste sum av flyt kostnad. Vanlig flyt kan implementeres med sirkulasjon (ved å legge på en «jukse»-kant fra s til t) og det er altså mer generelt. Dette er en klasse problemer med mange anvendelser. For vanlig flyt har vi to perspektiver: Maksimal flyt eller minimale snitt. Kanskje lettere å finne anvendelser for det siste. Residualnettverk: Antar kanter begge veier (der «manglende» kanter har c = 0) Residualkapasitet: r ij = c ij f ij + f ji Kun kanter med positiv residualkapasitet er med i residualnettverket Maks-flyt-løsning (Ford-Fulkerson): Gjenta: Øk flyten med min-kapasitet til en sti i residualnettverket Edmonds-Karp (polynomisk): Bruk BFS til å finne stiene Min-cut-max-flow: Den maksimale flyten = kapasiteten til det minste snittet Noen eksempelanvendelser av (helt vanlig) maks-flyt: Flyt med flere kilder/sluk, tilbud og etterspørsel (feasible flow problem) For alle noder i: sum flyt ut sum flyt inn = d(i) [evt. omvendt] F.eks. et transportproblem Løsning: Transformer problemet; vi kommer tilbake til dette Representanter En by har r innbyggere R i, q klubber C i og p politiske partier P i
Hver beboer er med i minst én klubb og kan tilhøre ett politisk parti Hver klubb må nominere ett av sine medlemmer til bystyret slik at antall i parti P k er u k Løsning: Flyt i flere nivå: s 1 C i 1 R j 1 P k uk t; sjekk f = q Toprosessor-scheduling Vi har et sett med prosessorer som skal kjøre på to prosessorer a i og b i : kostnad ved å kjøre prosess i på hhv prosessor a og b c ij : kommunikasjonskostnad mellom i og j hvis de er på ulike prosessorer Løsning: c(s, i) = a i, c(i, t) = b i, c(i, j) = c ij ; finn minimalt snitt Vi skal ikke se på generell løsning av sirkulasjonsproblemet her (selv om det finnes algoritmer for det) men to spesialtilfeller som likevel er mer generelle enn vanlig flyt: (1) flyt med nedre grenser, og (2) flyt med kostnad. Flyt med nedre grenser (lower bounds) Eksempelanvendelser: Matriseavrunding Vi har en p q-matrise med reelle tall D = {d ij } Radsummer a i og kolonnesummer b i Vi kan runde alle tallene opp eller ned etter ønske Krav: Sum av avrundede elementer = avrundet sum (rad, kolonne) La [x] = ( x, x ) Løsning: s [ai] i [dij] j [bi] t; finn lovlig flyt Tanker-scheduling Ferskvarer skal transporteres med båt Vi har flere fra-til-par med transitt-tider og fastsatte ankomst-datoer Finn det minimale antall skip som trengs Løsning: o G: Har kant (i, j) hvis j kan leveres i tide etter i (med samme skip) o En sti = ett skip; finn min. antall stier for å dekke alle noder o G : Splitt noder i og sett b(i, i ) = 1; legg til s og t; c(e) = 1 for alle Vi vil finne maksimal flyt men det er ikke sikkert vi kan finne noen flyt i det hele tatt. To trinn: (1) Finn lovlig (feasible) flyt; (2) finn maksimal flyt. Begge deler kan reduseres til et vanlig flytproblem med nedre grenser på 0. Vi ser på problem 2 først Flyt fra i til j: f ji Øvre og nedre kapasitet fra i til j: c ij, b ji Residualkapasitet: r ij = (c ij f ij ) + (f ji b ji ) [i stedet for c ij f ij + f ji ] Første ledd: Mulig økt flyt fra i til j pga. ledig kapasitet Andre ledd: Mulig økt flyt ved å oppheve flyt fra j til i
Vanlige flytalgoritmer kan basere seg kun på residualkapasitet (og se bort fra flyt, kapasiteter eller nedre grenser). Disse terminerer med optimale residualkapasiteter, og vi må rekonstruere flyten og det er flere måter å gjøre det på. Variabelskifte: For alle kanter (i, j) c ij = c ij b ij, r ij = r ij og f ij = f ij b ij Residualkapasiteten for (i, j) er: Ekvivalent: r ij = (c ij f ij ) + (f ji b ji ) r ij = c ij f ij + f ji og r ji = c ji f ji + f ij Vi uttrykker f ved hjelp av r og c : f ij = max(c ij r ij, 0) f ji = max(c ji r ji, 0) Vi konverterer tilbake til de opprinnelige variablene: f ij = b ij + max(c ij r ij b ij, 0) f ji = b ji + max(c ji r ji b ji, 0) Vi vil vise at løsningen på dette problemet også løser maks-flyst med nedre grenser. La f være en lovlig flyt i G med verdi v. La [S, S ] være et s-t snitt. La kapasiteten til [S, S ] være c[s, S ] = (i, j) (S, S ) c ij (i, j) (S, S) b ij. (1) Kapasiteten gir den maksimale «netto»-flyten som kan sendes ut av s. Flyten er gitt ved v = (i, j) (S, S ) f ij (i, j) (S, S) f ij. (2) Vi kan bruke f ij c ij i den første summen og b ij f ij i den andre, og får da: v (i, j) (S, S ) c ij (i, j) (S, S) b ij = c[s, S ] (3) Med andre ord er den maksimale flytverdien lavere enn eller lik kapasiteten til ethvert s-t snitt. Ved terminering vil en maks-flyt-algoritme finne et s-t snitt [S, S ] med r ij = 0 for alle kanter (i, j) (S, S ). La f være den tilhørende flyten med verdi v. Siden r ij = (c ij f ij ) + (f ji b ji ), så vil betingelsene f ij c ij og b ij f ij medføre at f ij = c ij og f ji = b ji. Dermed har vi at f ij = c ij for alle kanter (i, j) (S, S ) og f ij = b ij for alle kanter (i, j) (S, S). Hvis vi setter disse verdiene inn i (2), finner vi at v = c[s, S ] = (i, j) (S, S ) c ij (i, j) (S, S) b ij. I lys av ulikhet (3) betyr dette at [S, S ] er et minimalt s-t snitt og f er en maksimal flyt. Vi har nå også også vist en generalisering av max-flow min-cutteoremet:
Teorem: Hvis kapasitetene til et s-t snitt [S, S ] i et nettverk med både nedre og øvre grenser på kantflyt er definert av (1), vil maksimalverdien til flyt fra s til t være lik minimumskapasiteten over alle s-t snitt. Å finne en lovlig flyt 1 Repetisjon: Feasible flow-problemet (flyt med tilbud og etterspørsel) fra første forelesning. Vi gjør om problemet til et sirkulasjonsproblem (legg til bakoverkant (t, s) med uendelig kapasitet) og bruker en metode for å finne lovlig sirkulasjon. (Denne metoden fungerer, naturlig nok, for sirkulasjonsproblemet generelt.) Merk: Flyt inn i en node er nå lik flyt ut av noden for alle noder, inkludert s og t. Å finne en lovlig sirkulasjon består i å finne en flyt f som tilfredsstiller følgende beskrankninger: {j : (i, j) E} f ij {j : (j, i) E} f ji = 0 for alle i V, b ij f ij c ij for alle (i, j) E. Vi kan erstatte f ij med f ij + b ij i beskrankningene over og får følgende transformerte problem: {j : (i, j) E} f ij {j : (j, i) E} f ji = d(i) for alle i V, 0 f ij c ij b ij for alle (i, j) E, med tilbud (supply) d( ) der negativ d representerer etterspørsel i nodene definert ved d(i) = {j : (j, i) E} b ji {j : (i, j) E} b ij Summen av d( ) over alle noder blir 0, siden b ij er med to ganger én gang med positivt og én gang med negativt fortegn. Å finne en lovlig sirkulasjon er altså ekvivalent med å se om det transformerte problemet har en løsning f som tilfredsstiller de transformerte beskrankningene. Dette er det samme som feasible flow-problemet nevnt innledningsvis! Dette kan transformeres til et ordinært flytproblem ved å legge til nye kilde- og sluk-noder s og t. Noder med tilbud d(i) > 0 får en kant (s, i) med kapasitet d(i). Noder med etterspørsel d(i) < 0 får en kant (j, t) med kapasitet d(i). Vi finner så en maksimal flyt i dette nye nettverket. Hvis den maksimale flyten fyller alle kilde- og sluk-kanter så har vi en lovlig flyt i nettverket med tilbud og etterspørsel. Hvis f ij er en slik lovlig løsning vil f ij = f ij + b ij være en lovlig sirkulasjon for det opprinnelige sirkulasjonsnettverket (som altså er det opprinnelige flytnettverket + én tilbakekant phew!). 1 Forelesning 2
Billigst maks-flyt (optimal flyt, min-cost max-flow) Nedre grense 0, men kostnad på kantene. Kostnaden til en flyt er summen av w(e)f(e) for hver kant e. Kan for eksempel brukes til vektet bipartitt matching (selv om det finnes mer effektive algoritmer til det) og mer kompliserte scheduling- og allokeringsproblemer. Busacker & Gowen [GN s. 290] omtrent som Ford Fulkerson (FF), men i stedet for å bruke BFS for å finne korteste vei (i antall kanter) vil vi velge den billigste flytforøkende stien («kortest» hvis man bruker kostnad som kantlengde). Vi må da (1) vise at dette blir korrekt, og (2) finne en måte å gjøre det effektivt på. For enkelhets skyld ser vi her kun på korrekthet for punkt 2 (effektiviseringen), og antar følgende: Lemma: Hvis man velger korteste flytforøkende stier, med w(e) som kantlengde, vil man få en optimal (billigst mulig) flyt. Bevis: Se f.eks. GN. (Baserer seg i stor grad på teori rundt sirkulasjoner.) En optimal flyt med verdi v er den blant alle mulige med verdi v som har lavest kostnad. Som i FF lager vi oss et residualnettverk G = (V, E ) fra grafen G = (V, E), med litt ekstra prosessering pga. kostnadene (ser her på hver retning for seg): For hver kant e = (i, j) i E der f(e) < c(e) får kanten e = (i, j) i E kostnaden w (e ) = w(e) og kapasiteten c (e ) = c(e) f(e); For hver kant e = (i, j) i E der f(e) > 0 får kanten e = (j, i) i E kostnaden w (e ) = w(e) og kapasiteten c (e ) = f(e). Effektivisering Floyd-Warshall har en kubisk kjøretid vi vil gjerne ha noe bedre. Hvis vi kan anta at alle kostnader er positive kan vi bruke Dijkstras algoritme i første iterasjon. I senere iterasjoner får vi dessverre alltid negative kostnader nemlig på bakoverkantene. Heldigvis kan disse «omgås» med et lite triks: Vi erstatter w med en ikke-negativ kostnadsfunksjon w* som gir oss samme korteste sti. Anta at f er en optimal flyt med verdi v. Anta også at vi har funnet den korteste veien fra s til t i G med kantvekter gitt av w, og at vi har funnet alle avstander d (s, x). Dette kan vi få til med kvadratisk kompleksitet for f = 0 (med Dijkstras algoritme). La den nye flyten vi får være f, og la det nye residualnettverket være G = (V, E ) og la den nye kostnadsfunksjonen være w. Vi vil nå finne den korteste veien i dette nye nettverket med de nye kantvektene, og vi vil også finne alle avstandene d (s, x). For å få til det erstatter vi w (e) for alle kanter e = (i, j) med w*(e) (som altså er ikke-negativ det ser vi på snart): w*(e) = w (e) + d (s, i) d (s, j), og kaller avstandene under denne vektfunksjonen d*(s, x). Merk at at definisjonen vår medfører
w*(x) = w (X) d (s, x) for enhver sti X fra s til x i G. Mer spesifikt vil enhver minimal sti fra s til t i G med hensyn på w* også være en kortest sti med hensyn på w. Dessuten kan avstandene d (s, x) = d*(s, x) + d (s, x) med hensyn på w beregnes enkelt ut fra avstandene med hensyn på w*. Dermed har vi en ikke-negativ (ekvivalent) vektfunksjon vi kan bruke til å finne flytforøkende stier med, og vi kan bruke Dijkstras algoritme. For å se at w* faktisk er ikke-negativ, betrakt en vilkårlig kant e = (i, j) i G. Hvis den ikke finnes i den forrige flytforøkende stien (som ble brukt til å konstruere f og G ) eller e er en foroverkant så er den en kant i G også. I så fall er w (e) = w (e) og dermed får vi at d (s, i) + w (e) d (s, j), ut fra definisjonen av avstanden (jfr. trekantulikheten, selv om w kan være negativ); så w*(e) 0. Hvis (i, j) er en bakoverkant i den forøkende stien så er e = (j, i) en kant i G og d (s, i) = d (s, j) + w (e ), siden stien har minimal lengde med hesyn på w. Vi får da: w*(i, j) = w (i, j) + d (s, i) d (s, j) = w (j, i) + d (s, i) d (s, j) = w (j, i) + d (s, j) + w (j, i) d (s, j) = 0 Vi ender altså opp med en total kjøretid på O(v E log V ) for å finne den optimale flyten med verdi v.