A274101 TIETORAKENTEET JA ALGORITMIT GRAAFITEHTÄVIÄ JA -ALGORITMEJA Lähteet: Timo Harju, Opintomoniste Keijo Ruohonen, Graafiteoria (math.tut.fi/~ruohonen/gt.pdf) GRAAFIN LÄPIKÄYMINEN Perusta useimmille tehtäville ja algoritmeille Algoritmien tavoitteena on käydä läpi jokainen piste jotakin tiettyä tarkoitusta varten Graafin ajatellaan koostuvan kolmesta osasta: Puu (tree) jo läpikäydyt pisteet Reunus (fringe) pisteet etäisyydellä 1 puusta Tuntematon (unseen) kauempana olevat pisteet Läpikäymisessä on kaksi tasavahvaa strategiaa: BFS (breadth-first-search), leveyteen ensin haku DFS (depth-first-search), syvyyteen ensin haku 15.11.2005 KyAMK - TiRak, syksy 2005 2 GRAAFIN LÄPIKÄYMINEN BFS:ssä edetään ensin leveyssuunnassa DFS:ssä edetään ensin syvyyssuunnassa BFS:llä voidaan ratkaista esim. Mitkä ovat lyhimmät reitit tietystä pisteestä kaikkiin muihin pisteihin? (kriteerinä viivojen määrä) DFS:llä voidaan ratkaista esim. Onko verkko yhtenäinen? Mitkä ovat verkon yhtenäiset osaverkot? Onko verkossa silmukoita? TOPOLOGINEN JÄRJESTÄMINEN Määritetään osittainen järjestys suunnatun asyklisen graafin (DAG, Directed Asyclic Graph) pisteille Järjestämiskriteeri pisteille u ja v: u < v, jos on olemassa polku u v Sovelluksia Kurssien, osaprojektien, tms. suoritusjärjestys Yleisin algoritmi BFS-tyyppinen 15.11.2005 KyAMK - TiRak, syksy 2005 3 15.11.2005 KyAMK - TiRak, syksy 2005 4
LYHIN Etsitään graafissa oleva lyhin polku a) Kahden pisteen välillä b) Tietystä pisteestä kaikkiin muihin pisteisiin (sama suoritusaikaluokka!) Painotetussa graafissa etsitään kustannuksiltaan pienin polku Sovelluksena optimaalisen reitin haku Tietokone-, maantie-, lentokenttä- tms. verkko Algoritmit yleensä BFS-tyyppisiä, merkittävin Dijkstran algoritmi KRIITTINEN Verkko on ns. activity-node verkko Pisteissä aktiviteettiin kuluva aika Viivat ilmoittavat vain pisteiden väliset yhteydet Tehtävänä on Löytää nopein mahdollinen kokonaisaika alku- ja loppupisteen välillä ja vastaava polku (critical path) Selvittää, missä pisteissä ja kuinka paljon on löysää eli mitkä aktiviteetit ja kuinka paljon voivat viivästyä, että nopein kokonaisaika ei kasva Sovelluksia: projekti- ym. aikataulut Algoritmi löytyy mm. Weiss Data Structures and Algorithm Analysis in C++ 15.11.2005 KyAMK - TiRak, syksy 2005 5 15.11.2005 KyAMK - TiRak, syksy 2005 6 VIRTAUSONGELMAT (NETWORK FLOW) Määritetään verkon kapasiteetti kahden pisteen u ja v välillä, kun viivojen kapasiteetit c(u,v) annettu Esimerkkejä: Viivat putkia ja kapasiteetit niiden vetoisuuksia Viivat maanteitä ja kapasiteetit liikennevirtoja Algoritmi löytyy Weissin kirjasta PIENIN VIRITTÄVÄ PUU (MINIMUM SPANNING TREE) Muodostetaan suunnatusta graafista G viivoja karsimalla puu, joka yhdistää kaikki G:n pisteet minimikustannuksilla Sovellus: (liikenne?) verkosto yksinkertaistettuna lyhimmäksi mahdolliseksi siten, että yhtenäisyys säilyy Tunnetuimmat algoritmit Primin algoritmi Kruskalin algoritmi 15.11.2005 KyAMK - TiRak, syksy 2005 7 15.11.2005 KyAMK - TiRak, syksy 2005 8
KAHDENNETUT VERKOT (BICONNECTED GRAPH) Kahdennettussa verkossa minkään pisteen poistaminen ei katkaise yhteyttä muiden pisteiden välillä Sovellus esim. tietokoneverkko, missä toimimaton kone ei estä yhteyksiä muiden koneiden välillä Tehtävänä a) Tutkia, onko verkko kahdennettu b) Jos ei, mitkä ovat heikot paikat (articulation points) GRAAFIEN ALGORITMEJA Seuraavassa on esitettynä joitakin tärkeimmistä graafialgoritmeista pseudokoodina Pääosin algoritmit ovat Weissin kirjasta, mutta muitakin lähteitä on käytetty Eri alkuperästä johtuen yksityiskohtaisuus sekä käytetyt merkinnät vaihtelevat 15.11.2005 KyAMK - TiRak, syksy 2005 9 15.11.2005 KyAMK - TiRak, syksy 2005 10 GRAAFIEN ALGORITMEJA - GRAAFIEN ALGORITMEJA - Verkon BFS-läpikäynti (Breadth First Search): Samalla syntyy verkon BFS-hakupuu. void bfs( vertex v ) { Queue Q = empty; enqueue( v ); visited[v] = TRUE; /* in other words: mark( w ) */ while(! isempty Q ) { dequeue( v ); visit( v ); /* Do something */ for each vertex w adjacent to v visited[w] = TRUE; /* or: mark( w ) */ enqueue( w ); Verkon iteratiivinen DFS-läpikäynti (Depth First Search): Samalla syntyy verkon DFS-hakupuu. void dfs( vertex v ) { Stack S = empty; push( v ); visited[v] = TRUE; /* ( mark( w ) ) */ while(! isempty S ) { v = pop( ); visit( v ); /* Do something */ for each vertex adjacent to v visited[w] = TRUE; /* ( mark( w ) ) */ push( w ); 15.11.2005 KyAMK - TiRak, syksy 2005 11 15.11.2005 KyAMK - TiRak, syksy 2005 12
GRAAFIEN ALGORITMEJA - GRAAFIEN ALGORITMEJA TOPOLOGINEN JÄRJESTÄMINEN Verkon rekursiivinen DFS-läpikäynti: Samalla syntyy verkon DFS-hakupuu. void dfs( vertex v ) { visited[v] = TRUE; /* ( mark( w ) ) */ visit[v]; /* Do something */ dfs( w ); Topologinen järjestäminen void TopSort( graph G ) { Queue Q; int counter; Q = create_queue( NUM_VERTEX ); make_null( Q ); counter = 0; for each vertex v if ( indegree[v] == 0 ) enqueue( v, Q ); while (! isempty( Q ) ) { v = dequeue( Q ); topnum[v] = ++counter; for ( each w adjacent to v ) if ( --indegree[w] == 0 ) enqueue( w, Q ); if ( counter!= NUM_VERTEX ) error( graph has a cycle ); deletequeue( Q ); 15.11.2005 KyAMK - TiRak, syksy 2005 13 15.11.2005 KyAMK - TiRak, syksy 2005 14 GRAAFIEN ALGORITMEJA LYHIN GRAAFIEN ALGORITMEJA LYHIN Verkon solmu: typedef int vertex; struct table_entry { List header; int known; dist_type dist; vertex path; ; #define NOT_A_VERTEX 0 typedef struct table_entry TABLE[NUM_VERTEX+1]; Taulukon alustus: void init_table( vertex start, graph G, table T ) { int i; read graph( G, T ); for ( i = NUM_VERTEX; i > 0; i-- ) { T[i].known = FALSE; T[i].dist = INT_MAX; T[i].path = NOT_A_VERTEX; T[start].dist = 0; Lyhimmän polu tulostus: (kun algoritmi on suoritettu) void print_path( vertex v, TABLE T ) { if ( T[v].path!= NOT_A_VERTEX ) { print_path( T[v].path, T ); printf( to ); printf( %v, v ); /*%v pseudokoodia! */ 15.11.2005 KyAMK - TiRak, syksy 2005 15 15.11.2005 KyAMK - TiRak, syksy 2005 16
GRAAFIEN ALGORITMEJA LYHIN GRAAFIEN ALGORITMEJA Lyhin polku painottamattomassa verkossa: void unweighted( TABLE T ) { Queue Q; Q = create_queue( NUM_VERTEX ); make_null( Q ); enqueue( s ); /*Enqueue start vertex, determined elsewhere*/ while (! isempty( Q ) ) { v = dequeue( Q ); T[v].known = TRUE; /* Not needed? */ if ( T[w].dist == INT_MAX ) { T[w].dist = T[v].dist + 1; T[w].path = v; enqueue( w, Q ); deletequeue( Q ); Lyhin polku painotetussa verkossa (Dijkstran algoritmi): void dijkstra( TABLE T ) { for (; ; ) { V = smallest unknown distance vertex; if ( v == NOT_A_VERTEX ) break; T[v].known = TRUE; if (! T[w].known ) if ( T[v].dist + cv,w < T[w].dist ) { decrease ( T[w].dist to T[v].dist + cv,w ); T[w].path = v; 15.11.2005 KyAMK - TiRak, syksy 2005 17 15.11.2005 KyAMK - TiRak, syksy 2005 18