Föreläsning 5: Giriga algoritmer Kruskals och Prims algoritmer Spännande träd: Om G är en sammanhängande graf så är ett spännande träd ett träd som innehåller alla noder i V (G). Viantarattviharkantvikterw(e) på alla kanter i G. Hur hittar man spännande träd med minimal vikt? (Kallas Minimala Spännande Träd, MST.) Kruskals algoritm för MST Idén bakom denna algoritm är upprätthålla en spännande skog och förena delträden utan att skapa någon cykel tills ett enda stort träd bildats. Kruskal(V,E,w) (1) A (2) foreach v V (3) MakeSet(v) (4) Sortera E efter stigande vikt (5) foreach (u, v) E (ordnat efter stigande vikt w) (6) if FindSet(u) FindSet(v) (7) A A {(u, v)} (8) MakeUnion(u, v) (9) return A Tidskomplexitet: O( E log E ) (p.g.a. sorteringen); FindSet och MakeUnion tar O(log V ) tid. Korrekthetsbevis: Låt oss anta att T = {e 1,e 2,..., e p } är det träd som Kruskals algoritm ger. Låt T = {f 1,f 2,..., f p } vara ett annat spännande träd. Låt oss anta att kanterna i båda träden är sorterade i växande viktordning. Det kan hända att några av de första kanterna är samma i båda träden. De gemensamma kanterna bildar en mängd A. VikandåskrivaT = {A, e k,...} och T = {A, f k,...}. Viantarocksåatte k f k. Enligt definitionen av Kruskals algoritm måste w(e k ) w(f k ). Vi kan nu bilda grafen T {e k }.Denmåste innehålla en cykel C som innehåller e k men ingen av kanterna i A. Välj någon kant g e k i cykeln. Vi bildar trädet T = T {e k } {g}. Viserdåatt w(t ) w(t ). Fortsätt på samma sätt att sortera in fler kanter från T idet andra trädet. Till slut kommer vi att få T. Men då har vi visat att w(t ) w(t ). Alltså måste T vara minimalt.
Prims algoritm för MST Prims algoritm bygger på samma principer som Dijkstras algoritm. I varje steg läggs det hörn till trädet som ligger närmast (d.v.s. har lägst märkning key). Prim(V,E,w,s) (1) key[v] för varje v V (2) key[s] 0 (3) Q MakeHeap(V,key) (4) π[s] Null (5) while Q (6) v HeapExtractMin(Q) (7) foreach granne u till v (8) if u Q och w(u, v) <key[u] (9) π[u] v (10) key[u] w(u, v) (11) Justera heapen vid u Tidskomplexitet: O( V log V )+O( E log V ) =O( E log V ) Giriga algoritmer Denna typ av algoritmer arbetar efter följande princip: Gör i varje situation det som är lokalt optimalt, d.v.s. bäst för stunden. Några exempel vi redan sett: Kruskals algoritm Lägg till den lättaste kant som inte ger en cykel. Dijkstras algoritm Utvidga mängden S med det hörn som är märkt med lägst värde. Till många problem finns en naturlig girig algoritm, men ofta ger den inte en optimal lösning. Giriga algoritmer är ofta snabba så de kan användas för att snabbt få fram en approximativ lösning. Passande problem En girig algoritm passar i situationer där: 1. Problemet kan delas upp i ett första girigt val som lämnar kvar ett delproblem. 2. Det giriga valet alltid går att kombinera med en optimal lösning. 3. Den optimala lösningen på delproblemet går alltid att kombinera med det giriga valet och ger då en optimal lösning.
Exempel: Ett triangelproblem Problem: Hitta stigen från toppen till botten som maximerar summan av de ingående talen. 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 Låt n vara antalet rader. Det finns 2 n 1 olika stigar att prova. Girig algoritm för triangelproblemet Gå i varje steg till det största av de två talen på raden nedanför. 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 Den giriga algoritmen ger här summan 28 medan den bästa stigen ger 30 (7+ 3+8+7+5). Tidskomplexiteten för den giriga algoritmen är Θ(n).
Aktivitetsplanering Vi har n st aktiviteter a 1,a 2,..., a n som äger rum under tidsintervall på formen [s i,f i ). Inga intervall får överlappar varandra. (Intervallen är definierade som halvöppna. Det innebär t.ex. att [2, 4) och [4, 5) inte överlappar varandra.) Hur väljer man ut ett maximalt antal aktiviteter som inte överlappar varandra? Girig algoritm för aktivitetsplanering Sortera efter sluttid så att f 1 f 2... f n. (1) A {a 1 } (2) i 1 (3) for m 2 to n (4) if s m f i (5) A {a m } (6) i m (7) return A Girig algoritm för intervalltäckning Givet är n punkter på tallinjen. Vi vill hitta ett minimalt antal intervall av längd 1 vars union innehåller alla punkterna. Girig algoritm: (1) Sortera punkterna i växande ordning. (2) while någon punkt finns kvar (3) Placera ett intervall med vänstra ändpunkten i punkten med lägst koordinat. (4) Ta bort alla punkterna som täcks av detta intervall. Algoritmen ger den minimala övertäckningen eftersom något intervall måste täcka punkten längst till vänster; den giriga placeringen av intervallet täcker alla punkter som skulle täckas av någon annan placering. Varför fungerar algoritmerna? Generell form: Ett problem kan lösas girigt om 1. Problemet kan lösas genom att man gör ett val och sedan har ett delproblem av samma typ kvar att lösa. 2. Det första valet kan göras girigt och det giriga valet går alltid att kombinera med en optimal lösning.
En annan generell typ av problem Vi har en grundmängd E. Vi har en uppsättning tillåtna (oberoende) mängder F.Viharvikterw(e) på elementen. Maximal tillåten mängd: A F är maximal om A {x} / F för varje x/ A. Problem: Hur hittar man en maximal tillåten mängd med minimal viktsumma. (1) A (2) Sortera E efter stigande vikt (3) foreach e E (ordnat efter stigande vikt w) (4) if A {e} F (5) A A {e} (6) return A När fungerar denna algoritm? Jo, precis då F bildar en matroid. Matroider Låt M vara en mängd och F en familj av delmängder till M. (M,F) bildar en matroid om 1. A F och B A medför B F. 2. Om A, B F och A < B så finns det x B \ A så att A x F. F kallas för familjen av oberoende mängder i matroiden. Ex: G är en graf M = E(G) och F är mängden av delgrafer utan cykler. Ex: M är en mängd vektorer och F är familjen av oberoende mängder av vektorer. Vi kan nu bevisa att den giriga algoritmen fungerar för matroider: Bevis: Det går att visa att maximala oberoende mängder har samma storlek. Antag att A = {a 1,a 2,...a p } är en maximal oberoende mängd som ges av algoritmen och att B = {b 1,b 2,..., b p } är en maximal oberoende mängd med lägre vikt. Antag att kanterna är sorterade efter ökande vikt i båda mängderna. Det måste finnas ett minsta tal j så att w(b j ) <w(a j ).SättdåA = {a 1,...a j 1 } och B = {b 1,..., b j }. Båda mängderna är oberoende och B > A. Det finns då b k B så att {a 1,..., a j 1,b k } F.Menw(a j ) >w(b j ) w(b k ).Detbetyder att algoritmen måste ha valt b k redan vilket är omöjligt. Någon sådan mängd B kan därför inte finnas.