Kapitel 10: Graphalgorithmen

Slides:



Advertisements
Ähnliche Präsentationen
Klassen - Verkettete Liste -
Advertisements

Berechne den optimalen (kürzesten, schnellsten) Weg
Man bestimme den „minimalen aufspannenden Baum“ des Graphen.
Single-Source Shortest Paths: SSSP
Programmierung 1 - Repetitorium WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage:
Minimum Spanning Tree: MST
Prof. Dr. S. Albers Prof.Dr.Th Ottmann
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (26-Graphenalgorithmen: Wiederholung und Übung) Prof. Th. Ottmann.
Kapitel 9: Graphdurchlauf
Einführung in die Informatik: Programmierung und Software-Entwicklung
ACM ICPC Praktikum Kapitel 8: Backtracking. Übersicht Backtracking Aufzählung aller Teilmengen Aufzählung aller Permutationen n-Königinnen-Problem.
Claudio Moraga; Gisbert Dittrich
Graphen Ein Graph ist eine Kollektion von Knoten und Kanten. Knoten sind einfache Objekte. Sie haben Namen und können Träger von Werten, Eigenschaften.
ADS Vorlesung Prof. Dr. W. Conen, FH Gelsenkirchen
Suche in Texten (Stringsuche )
Lösung 5.1Schleifen 1.while (x < 5)if (x < 5) thenwhile Bif B then { do {{do { x = x + 1; x = x + 1; A A }}}} while (x < 5) while B do {x = x + 1;do {A.
Marco Barz Seminar über Algorithmen SoSe2007
Programmieren 2 Future Car Projekt Praktikum 6
Binäre Bäume Richard Göbel.
WS Algorithmentheorie 13 - Kürzeste (billigste) Wege Prof. Dr. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (27 – Kürzeste Wege) Prof. Th. Ottmann.
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (17 – Bäume: Grundlagen und natürliche Suchbäume) Prof. Th. Ottmann.
1 Vorlesung Informatik 2 Algorithmen und Datenstrukturen (21 – Kürzeste Wege) T. Lauer.
Algorithmentheorie 12 – Spannende Bäume minimalen Gewichts
Algorithmen und Datenstrukturen
WS03/041 Binomial Queues Prof. Dr. S. Albers Prof.Dr.Th Ottmann.
Friedhelm Meyer auf der Heide 1 HEINZ NIXDORF INSTITUTE University of Paderborn Algorithms and Complexity Algorithmen und Komplexität Teil 1: Grundlegende.
Friedhelm Meyer auf der Heide 1 HEINZ NIXDORF INSTITUTE University of Paderborn Algorithms and Complexity Algorithmen und Komplexität Teil 1: Grundlegende.
Friedhelm Meyer auf der Heide 1 HEINZ NIXDORF INSTITUTE University of Paderborn Algorithms and Complexity Algorithmen und Komplexität Teil 1: Grundlegende.
High Performance = Innovative Computer Systems + Efficient Algorithms Friedhelm Meyer auf der Heide 1 HEINZ NIXDORF INSTITUT Universität Paderborn Algorithmen.
Minimum Spanning Tree: MST
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Kapitel 2: Datenstrukturen
FH-Hof Sortieren mit Binären Bäumen Richard Göbel.
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik II Vorlesung 1 SS 2001 Algorithmus von Dijkstra.
Effiziente Algorithmen
LS 2 / Informatik Datenstrukturen, Algorithmen und Programmierung 2 (DAP2)
Abteilung für Telekooperation Übung Softwareentwicklung 1 für Wirtschaftsinformatik Dr. Wieland Schwinger
Flüsse, Schnitte, bipartite Graphen
Effiziente Algorithmen
Chromatische Zahl.
Diskrete Mathematik II
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Effiziente Algorithmen
Effiziente Algorithmen Hartmut Klauck Universität Frankfurt SS
Animation von Dijkstra
Einführung in die Informatik für Naturwissenschaftler und Ingenieure
Einführung in die Informatik für Naturwissenschaftler und Ingenieure
Animation von Dijkstra
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Einführung in die Informatik für Naturwissenschaftler und Ingenieure (alias Einführung in die Programmierung) (Vorlesung) Prof. Dr. Günter Rudolph Fachbereich.
Institut für Theoretische Informatik
Algorithmen und Datenstrukturen Übungsmodul 6
Robust Branch-Cut-and-Price Algorithms for Vehicle Routing Problems Christian Gruber - Johannes Reiter.
Travelling Salesman Problem (TSP)
Kapitel 8: Graphalgorithmen 8. 1 Grundlagen 8
Graphen (1) 1 Helmut Schauer Educational Engineering Lab
Kapitel 8: Graphalgorithmen 8. 1 Grundlagen 8
Data Mining Spectral Clustering Junli Zhu SS 2005.
Analyse der Laufzeit von Algorithmen
10 Graphen gerichtete und ungerichtete, mit Marken an Ecken und/oder Kanten Anwendungsgebiete: Verkehrsnetze, Kommunikationsnetze, Netzpläne, Spiele,...
Bipartite Graphen Der Satz von König.
Eine kurze Geschichte der Graphentheorie
Algorithmen und Datenstrukturen 1 SS 2002
Institut für Kartographie und Geoinformation Prof. Dr. Lutz Plümer Diskrete Mathematik II Vorlesung Datenstrukturen für den Algorithmus von.
Programmiersprachen II Graph_Algorithmen Gewichtete Graphen - Minimum Spanning Tree und shortest path aus Implementierungssicht Prof. Dr. Reiner Güttler.
Programmiersprachen II Graph_Algorithmen Einführung Prof. Dr. Reiner Güttler Fachbereich GIS HTW.
Übungen Übungsanmeldung Übungskorrektur
 Präsentation transkript:

Kapitel 10: Graphalgorithmen ACM ICPC Praktikum Kapitel 10: Graphalgorithmen

Übersicht Bäume Minimale Spannbäume Zusammenhang Kürzeste Wege Kreise Planare Graphen Netzwerkfluss und bipartites Matching

Bäume Ein Baum ist ein zusammen- hängender Graph, der keine Kreise enthält. Jeder Baum mit n Knoten hat also genau n-1 Kanten. Ein Baum hat oft einen ausge- zeichneten Knoten, der die Wurzel repräsentiert. Jeder Knoten mit Grad 1 im Baum heißt Blatt.

Bäume Gewurzelter Baum: gerichteter Baum, in dem jeder Knoten bis auf Wurzel Eingrad 1 hat. Binärer Baum: Jeder Knoten hat Ausgrad 2 oder 0. Spannbaum eines Graphen G=(V,E): Teilgraph von G, der ein Baum ist und alle Knoten von G enthält.

Minimaler Spannbaum Gegeben: Graph G=(V,E) mit Kantenkosten c:E ! IR Gesucht: Spannbaum T in G mit minimaler Summe der Kantenkosten Algorithmen: Starte mit leerer Kantenmenge. Wiederhole, bis Spannbaum erreicht: Kruskal: füge Kante mit minimalem Gewicht unter Wahrung der Kreisfreiheit hinzu Prim: erweitere Baum um minimale Kante

Prims Algorithmus #define MAXV 100 /* maximum number of vertices */ #define MAXDEGREE 50 /* maximum outdegree of a vertex */ typedef struct { int v; /* neighboring vertex */ int weight; /* edge weight */ } edge; edge edges[MAXV+1][MAXDEGREE]; /* adjacency info */ int degree[MAXV+1]; /* outdegree of each vertex */ int nvertices; /* number of vertices in the graph */ int nedges; /* number of edges in the graph */ } graph;

Prims Algorithmus int parent[MAXV]; /* discovery relation */ prim(graph *g, int start) { int i,j; /* counters */ bool intree[MAXV]; /* is the vertex in the tree yet? */ int distance[MAXV]; /* distance vertex is from start */ int v; /* current vertex to process */ int w; /* candidate next vertex */ int weight; /* edge weight */ int dist; /* best current distance from start */ for (i=1; i<=g->nvertices; i++) { intree[i] = FALSE; distance[i] = MAXINT; parent[i] = -1; } distance[start] = 0; v = start;

Prims Algorithmus while (intree[v] == FALSE) { intree[v] = TRUE; for (i=0; i<g->degree[v]; i++) { w = g->edges[v][i].v; weight = g->edges[v][i].weight; if ((distance[w] > weight) && (intree[w] == FALSE)) { distance[w] = weight; parent[w] = v; } v = 1; dist = MAXINT; for (i=1; i<=g->nvertices; i++) if ((intree[i] == FALSE) && (dist > distance[i])) { dist = distance[i]; v = i;

Prims Algorithmus main() { graph g; int i; read_graph(&g,FALSE); prim(&g,1); printf("Out of Prim\n"); for (i=1; i<=g.nvertices; i++) { /*printf(" %d parent=%d\n",i,parent[i]);*/ find_path(1,i,parent); } printf("\n");

MST Probleme Maximum Spanning Tree: Maximiere Kosten eines Spannbaums. Minimum Product Spanning Tree: Minimiere Produkt der Kantenkosten (´ minimiere Summe der Logarithmen) Minimum Bottleneck Spanning Tree: Minimiere maximale Kantenkosten (MST minimiert auch max. Kantenkosten)

Zusammenhang Ein ungerichteter (gerichteter) Graph ist (stark) zusammenhängend, wenn es einen ungerichteten (gerichteten) Weg zwischen zwei beliebigen Knotenpaaren gibt. Jeder Graph, der auch nach Löschung eines beliebigen Knotens noch zusammenhängend ist, heißt zweifach zusammenhängend. Eine Kante, dessen Löschung den Graphen in zwei Teilgraphen zerteilt, heißt Brücke.

Test auf Zusammenhang Einfacher Zusammenhang: DFS, BFS Starker Zusammenhang: Finde gerichteten Kreis mittels DFS. Schrumpfe solch einen Kreis zu einem einzelnen Knoten und wiederhole, bis kein gerichteter Kreis mehr gefunden. Ergibt einzelnen Knoten: Graph start zusammenhängend. k-facher Zusammenhang: Teste, ob jedes Knotenpaar Fluss der Größe >=k hat.

Kürzeste Wege Gegeben: Graph G=(V,E) mit Kantenkosten c:E ! IR Weg von v nach w ist kürzester Weg, wenn Summe der Kantenkosten minimal. Single-source-shortest-path: Dijkstra Idee: arbeite ähnlich zu Prim, um einen kürzeste-Wege-Baum aufzubauen All-pairs-shortest-path: Floyd-Warshall Idee: verwende Matrixmultiplikation

Dijkstras Algorithmus int parent[MAXV]; /* discovery relation */ dijkstra(graph *g, int start) /* was prim(g,start) */ { int i,j; /* counters */ bool intree[MAXV]; /* is the vertex in the tree yet? */ int distance[MAXV]; /* distance vertex is from start */ int v; /* current vertex to process */ int w; /* candidate next vertex */ int weight; /* edge weight */ int dist; /* best current distance from start */ for (i=1; i<=g->nvertices; i++) { intree[i] = FALSE; distance[i] = MAXINT; parent[i] = -1; } distance[start] = 0; v = start;

Dijkstras Algorithmus while (intree[v] == FALSE) { intree[v] = TRUE; for (i=0; i<g->degree[v]; i++) { w = g->edges[v][i].v; weight = g->edges[v][i].weight; if (distance[w] > (distance[v]+weight)) { distance[w] = distance[v]+weight; parent[w] = v; } v = 1; dist = MAXINT; for (i=1; i<=g->nvertices; i++) if ((intree[i] == FALSE) && (dist > distance[i])) { dist = distance[i]; v = i; /*for (i=1; i<=g->nvertices; i++) printf("%d %d\n",i,distance[i]);*/

Dijkstras Algorithmus main() { graph g; int i; read_graph(&g,FALSE); dijkstra(&g,1); for (i=1; i<=g.nvertices; i++) find_path(1,i,parent); printf("\n"); }

Floyd-Warshall Algorithmus #define MAXV 100 /* maximum number of vertices */ #define MAXDEGREE 50 /* maximum outdegree of a vertex */ #define MAXINT 100007 typedef struct { int v; /* neighboring vertex */ int weight; /* edge weight */ bool in; /* is the edge "in" the solution? */ } edge; edge edges[MAXV][MAXDEGREE]; /* adjacency info */ int degree[MAXV]; /* outdegree of each vertex */ int nvertices; /* number of vertices in the graph */ int nedges; /* number of edges in the graph */ } graph; int weight[MAXV+1][MAXV+1]; /* adjacency/weight info */ int nvertices; /* number of vertices in the graph */ } adjacency_matrix;

Floyd-Warshall Algorithmus initialize_adjacency_matrix(adjacency_matrix *g) { int i,j; /* counters */ g -> nvertices = 0; for (i=1; i<=MAXV; i++) for (j=1; j<=MAXV; j++) g->weight[i][j] = MAXINT; } read_adjacency_matrix(adjacency_matrix *g, bool directed) int i; /* counter */ int m; /* number of edges */ int x,y,w; /* placeholder for edge and weight */ initialize_adjacency_matrix(g); scanf("%d %d\n",&(g->nvertices),&m); for (i=1; i<=m; i++) { scanf("%d %d %d\n",&x,&y,&w); g->weight[x][y] = w; if (directed==FALSE) g->weight[y][x] = w;

Floyd-Warshall Algorithmus print_graph(adjacency_matrix *g) { int i,j; /* counters */ for (i=1; i<=g->nvertices; i++) { printf("%d: ",i); for (j=1; j<=g->nvertices; j++) if (g->weight[i][j] < MAXINT) printf(" %d",j); printf("\n"); } print_adjacency_matrix(adjacency_matrix *g) int i,j; /* counters */ printf("%3d: ",i); printf(" %3d",g->weight[i][j]);

Floyd-Warshall Algorithmus floyd(adjacency_matrix *g) { int i,j; /* dimension counters */ int k; /* intermediate vertex counter */ int through_k; /* distance through vertex k */ for (k=1; k<=g->nvertices; k++) for (i=1; i<=g->nvertices; i++) for (j=1; j<=g->nvertices; j++) { through_k = g->weight[i][k]+g->weight[k][j]; if (through_k < g->weight[i][j]) g->weight[i][j] = through_k; }

Floyd-Warshall Algorithmus main() { adjacency_matrix g; read_adjacency_matrix(&g,FALSE); print_graph(&g); floyd(&g); print_adjacency_matrix(&g); }

Kreise Alle Graphen, die keine Bäume sind, enthalten Kreise. Eulerkreis: Kreis, der jede Kante genau einmal durchläuft. Hamiltonscher Kreis: Kreis, der jeden Knoten genau einmal durchläuft.

Eulerkreis Eulerkreis im ungerichteten Graphen: Existiert, wenn alle Knoten geraden Grad haben. Algorithmus: Beginne bei beliebigem Knoten, erweitere Kreis um beliebige Kante, bis wieder am Ausgangspunkt. Wiederholung ergibt kantendisjunkte Kreise, die beliebige verschmolzen werden können. Eulerkreis im gerichteten Graphen: Existiert, falls für jeden Knoten der Eingrad gleich dem Ausgrad ist. Dann wie oben.

Hamiltonscher Kreis NP-vollständiges Problem, d.h. es gibt aller Voraussicht nach keinen Polynomialzeitalgorithmus dafür. Backtracking (mittels Durchlauf aller möglichen Knotenpermutationen) kann verwendet werden, falls Graph genügend klein ist.

Planare Graphen Ein Graph ist planar, falls die Knoten und Kanten so in 2D-Raum eingebettet werden können, dass es keine Kantenüberschneidungen gibt. Ein Baum ist ein planarer Graph. Sei n Anzahl Knoten, m Anzahl Kanten und f Anzahl Facetten, dann gilt n-m+f=2. Jeder planare Graph erfüllt m <= 3n-6. Ein Graph ist planar genau dann, wenn er keinen K3,3 oder K5 als Graphminor enthält.

Netzwerkfluss Gegeben: gerichteter Graph G=(V,E) mit Kantenkapazitäten c:E ! IR+ und Quell-Ziel-Paar (s,t) Gesucht: Fluss f:E ! IR+ mit maximalem Flusswert von s nach t. Fluss f ist legal, falls (u,v) f(u,v) = (v,w) f(v,w) für alle v 2 V n {s,t} f(e) <= c(e) für alle e 2 E Flusswert von f ist (s,w) f(s,w) - (u,s) f(u,s)

Netzwerkfluss O.B.d.A. sei G ein einfacher gerichteter Graph, ansonsten Transformation: Residuales Netzwerk von f: G’=(V,E’) mit c’:E ! IR+, wobei c’(u,v)=c(u,v)-f(u,v) falls (u,v) 2 E, c’(u,v) = f(v,u) falls (v,u) 2 E, und sonst c’(u,v) = 0. neu

Netzwerkfluss Augmentierender Pfad p=(v1,…,vk) in G’: Pfad mit positiven Kantenkosten Residuale Kapazität von p: cp = mini c’(vi,vi+1) Neuer Fluss f’ =f+p: f’(u,v) = f(u,v)+cp falls (u,v) 2 p und f’(u,v) = f(u,v)-cp falls (v,u) 2 p Es gilt: Flusswert von f’ > Flusswert von f und f maximal , kein augm. Pfad in G’

Ford-Fulkerson Algorithmus #define MAXV 100 /* maximum number of vertices */ #define MAXDEGREE 50 /* maximum outdegree of a vertex */ typedef struct { int v; /* neighboring vertex */ int capacity; /* capacity of edge */ int flow; /* flow through edge */ int residual; /* residual capacity of edge */ } edge; edge edges[MAXV][MAXDEGREE]; /* adjacency info */ int degree[MAXV]; /* outdegree of each vertex */ int nvertices; /* number of vertices in the graph */ int nedges; /* number of edges in the graph */ } flow_graph;

Ford-Fulkerson Algorithmus main() { flow_graph g; /* graph to analyze */ int source, sink; /* source and sink vertices */ int flow; /* total flow */ int i; /* counter */ scanf("%d %d",&source,&sink); read_flow_graph(&g,TRUE); netflow(&g,source,sink); print_flow_graph(&g); flow = 0; for (i=0; i<g.nvertices; i++) flow += g.edges[source][i].flow; printf("total flow = %d\n",flow); }

Ford-Fulkerson Algorithmus initialize_graph(g) flow_graph *g; /* graph to initialize */ { int i; /* counter */ g -> nvertices = 0; g -> nedges = 0; for (i=0; i<MAXV; i++) g->degree[i] = 0; } read_flow_graph(g,directed) bool directed; /* is this graph directed? */ int m; /* number of edges */ int x,y,w; /* placeholder for edge and weight */ initialize_graph(g); scanf("%d %d\n",&(g->nvertices),&m); for (i=1; i<=m; i++) { scanf("%d %d %d\n",&x,&y,&w); insert_flow_edge(g,x,y,directed,w);

Ford-Fulkerson Algorithmus insert_flow_edge(flow_graph *g, int x, int y, bool directed, int w) { if (g->degree[x] > MAXDEGREE) printf("Warning: insertion(%d,%d) exceeds degree bound\n",x,y); g->edges[x][g->degree[x]].v = y; g->edges[x][g->degree[x]].capacity = w; g->edges[x][g->degree[x]].flow = 0; g->edges[x][g->degree[x]].residual = w; g->degree[x] ++; if (directed == FALSE) insert_flow_edge(g,y,x,TRUE,w); else g->nedges ++; }

Ford-Fulkerson Algorithmus edge *find_edge(flow_graph *g, int x, int y) { int i; /* counter */ for (i=0; i<g->degree[x]; i++) if (g->edges[x][i].v == y) return( &g->edges[x][i] ); return(NULL); } add_residual_edges(flow_graph *g) int i,j; /* counters */ for (i=1; i<=g->nvertices; i++) for (j=0; j<g->degree[i]; j++) if (find_edge(g,g->edges[i][j].v,i) == NULL) insert_flow_edge(g,g->edges[i][j].v,i,TRUE,0);

Ford-Fulkerson Algorithmus print_flow_graph(flow_graph *g) { int i,j; /* counters */ for (i=1; i<=g->nvertices; i++) { printf("%d: ",i); for (j=0; j<g->degree[i]; j++) printf(" %d(%d,%d,%d)",g->edges[i][j].v, g->edges[i][j].capacity, g->edges[i][j].flow, g->edges[i][j].residual); printf("\n"); } bool processed[MAXV]; /* which vertices have been processed */ bool discovered[MAXV]; /* which vertices have been found */ int parent[MAXV]; /* discovery relation */ bool finished = FALSE; /* if true, cut off search immediately */

Ford-Fulkerson Algorithmus initialize_search(g) flow_graph *g; /* graph to traverse */ { int i; /* counter */ for (i=1; i<=g->nvertices; i++) { processed[i] = FALSE; discovered[i] = FALSE; parent[i] = -1; }

Ford-Fulkerson Algorithmus bfs(flow_graph *g, int start) { queue q; /* queue of vertices to visit */ int v; /* current vertex */ int i; /* counter */ init_queue(&q); enqueue(&q,start); discovered[start] = TRUE; while (empty(&q) == FALSE) { v = dequeue(&q); process_vertex(v); processed[v] = TRUE; for (i=0; i<g->degree[v]; i++) if (valid_edge(g->edges[v][i]) == TRUE) { if (discovered[g->edges[v][i].v] == FALSE) { enqueue(&q,g->edges[v][i].v); discovered[g->edges[v][i].v] = TRUE; parent[g->edges[v][i].v] = v; } if (processed[g->edges[v][i].v] == FALSE) process_edge(v,g->edges[v][i].v);

Ford-Fulkerson Algorithmus bool valid_edge(edge e) { if (e.residual > 0) return (TRUE); else return(FALSE); } process_vertex(v) int v; /* vertex to process */ process_edge(x,y) int x,y; /* edge to process */

Ford-Fulkerson Algorithmus find_path(start,end,parents) int start; /* first vertex on path */ int end; /* last vertex on path */ int parents[]; /* array of parent pointers */ { if ((start == end) || (end == -1)) printf("\n%d",start); else { find_path(start,parents[end],parents); printf(" %d",end); } int path_volume(flow_graph *g, int start, int end, int parents[]) edge *e; /* edge in question */ edge *find_edge(); if (parents[end] == -1) return(0) e = find_edge(g,parents[end],end); if (start == parents[end]) return(e->residual); else return( min(path_volume(g,start,parents[end],parents), e->residual) );

Ford-Fulkerson Algorithmus augment_path(flow_graph *g, int start, int end, int parents[], int volume) { edge *e; /* edge in question */ edge *find_edge(); if (start == end) return; e = find_edge(g,parents[end],end); e->flow += volume; e->residual -= volume; e = find_edge(g,end,parents[end]); e->residual += volume; augment_path(g,start,parents[end],parents,volume); }

Ford-Fulkerson Algorithmus netflow(flow_graph *g, int source, int sink) { int volume; /* weight of the augmenting path */ add_residual_edges(g); initialize_search(g); bfs(g,source); volume = path_volume(g, source, sink, parent); while (volume > 0) { augment_path(g,source,sink,parent,volume); }

Anwendungen Maximum Matching in bipartiten Graphen. Gegeben: Graph G=(V,E) Matching: Teilmenge E’ ½ E, so dass jeder Knoten max. Grad 1 hat. G bipartit genau dann, wenn zweifärbbar (d.h. zwei Farben reichen, Knoten so zu färben, dass keine zwei adjazenten Knoten dieselbe Farbe haben)