/// <summary> /// Konstruuje ścieżkę od źródła do danego wierzchołka /// </summary> /// <param name="s">Wierzchołek początkowy (źródło)</param> /// <param name="t">Wierzołek końcowy (cel)</param> /// <param name="pi">Tablica odległości od źródła</param> /// <exception cref="ArgumentException"></exception> /// <returns>Szukana ścieżka</returns> /// <remarks> /// Ścieżka reprezentowana jest jako tablica krawędzi, /// kolejne elementy tej tablicy to kolejne krawędzie na ścieżce.<para/> /// Jeśli ścieżka nie istnieje metoda zwraca null.<para/> /// Jeśli wierzchołek końcowy jest równy początkowemu metoda zwraca pustą (zeroelementową) tablicę. /// </remarks> /// <seealso cref="ConstructPath(int,int,PathsInfo[,])"/> /// <seealso cref="PathsInfo"/> /// <seealso cref="ASD.Graphs"/> public static Edge[] ConstructPath(int s, int t, PathsInfo[] pi) { if (pi[s].Dist != 0.0 || pi[s].Last != null) { throw new ArgumentException("Incorrect paths infos (invalid source vertex)"); } if (pi[t].Dist.IsNaN()) { return(null); } if (s == t) { return(new Edge[0]); } var edgesStack = new EdgesStack(); for (var vert = t; vert != s; vert = pi[vert].Last.Value.From) { edgesStack.Put(pi[vert].Last.Value); } return(edgesStack.ToArray()); }
/// <summary> /// Konstruuje ścieżkę pomiędzy wskazaną parą wierzchołków /// </summary> /// <param name="s">Wierzchołek początkowy (źródło)</param> /// <param name="t">Wierzołek końcowy (cel)</param> /// <param name="pi">Tablica odległości</param> /// <returns>Szukana ścieżka</returns> /// <remarks> /// Ścieżka reprezentowana jest jako tablica krawędzi, /// kolejne elementy tej tablicy to kolejne krawędzie na ścieżce.<para/> /// Jeśli ścieżka nie istnieje metoda zwraca null.<para/> /// Jeśli wierzchołek końcowy jest równy początkowemu metoda zwraca pustą (zeroelementową) tablicę. /// </remarks> /// <seealso cref="ConstructPath(int,int,PathsInfo[])"/> /// <seealso cref="PathsInfo"/> /// <seealso cref="ASD.Graphs"/> public static Edge[] ConstructPath(int s, int t, PathsInfo[,] pi) { if (pi[s, t].Dist.IsNaN()) { return(null); } if (s == t) { return(new Edge[0]); } var edgesStack = new EdgesStack(); for (var vert = t; vert != s; vert = pi[s, vert].Last.Value.From) { edgesStack.Put(pi[s, vert].Last.Value); } return(edgesStack.ToArray()); }
/// <summary> /// Znajduje scieżkę Eulera w grafie /// </summary> /// <param name="g">Badany graf</param> /// <param name="ec">Znaleziona ścieżka (parametr wyjściowy)</param> /// <returns>Informacja czy ścieżka Eulera istnieje</returns> /// <remarks> /// Jeśli w badanym grafie nie istnieje ścieżka Eulera metoda zwraca <b>false</b>, parametr <i>ec</i> ma wówczas wartość <b>null</b>.<br/> /// <br/> /// Metoda nie modyfikuje badanego grafu.<br/> /// <br/> /// Metoda implementuje algorytm Fleury'ego. /// </remarks> public static bool Lab04_Euler(this Graph g, out Edge[] ec) { // tylko cykl - 2 pkt // cykl i sciezka - 3 pkt /* * Algorytm Fleury'ego * * utworz pusty stos krawedzi Euler * utworz pusty stos krawedzi pom * w = dowolny wierzcholek grafu * umiesc na stosie pom sztuczna krawedz <w,w> * dopoki pom jest niepusty powtarzaj * w = wierzch. koncowy krawedzi ze szczytu stosu pom (bez pobierania krawedzi ze stosu) * jesli stopien wychodzacy w > 0 * e = dowolna krawedz wychodzaca z w * umiesc krawedz e na stosie pom * usun krawedz e z grafu * w przeciwnym przypadku * pobiez szczytowy element ze stosu pom i umiesc go na stosie Euler * usun ze stosu Euler sztuczna krawedz (petle) startowa (jest na szczycie) * * wynik: krawedzie tworzace cykl sa na stosie Euler * * Uwaga: powyzszy algorytm znajduje cykl Eulera (jesli istnieje), * aby znalezc sciezke nalezy najpierw wyznaczyc wierzcholek startowy * (nie mozna wystartowac z dowolnego) */ EdgesStack Euler = new EdgesStack(); EdgesStack pom = new EdgesStack(); int w = 0; pom.Put(new Edge(w, w)); Graph clonedGraph = g.Clone(); // Trzeba byłoby sprawdzić jeszcze czy g jest Eulerowski (czy wszystkie wierzchołki są // stopnia parzystego) while (!pom.Empty) { w = pom.Peek().To; if (clonedGraph.OutDegree(w) > 0) { Edge e = clonedGraph.OutEdges(w).First(); pom.Put(e); clonedGraph.DelEdge(e); } else { Euler.Put(pom.Get()); } } Euler.Get(); ec = Euler.ToArray(); if (ec.First().From == ec.Last().To) { return(true); } else { ec = null; return(false); } }
/// <summary> /// Wyznacza najkrótszą ścieżkę do wskazanego wierzchołka algorytmem A* /// </summary> /// <param name="g">Badany graf</param> /// <param name="s">Wierzchołek źródłowy</param> /// <param name="t">Wierzchołek docelowy</param> /// <param name="p">Znaleziona ścieżka (parametr wyjściowy)</param> /// <param name="h">Oszacowanie odległości wierzchołków (funkcja)</param> /// <returns>Informacja czy ścieżka do wierzchołka docelowego istnieje</returns> /// <remarks> /// Domyślna wartość parametru h (null) oznacza, że zostanie przyjęte oszacowanie zerowe. /// Algorytm A* sprowadza się wówczas do algorytmu Dijkstry.<para/> /// Metoda nie bada spełnienia założeń algorytmu A* - jeśli nie one są spełnione /// może zwrócić błędny wynik (nieoptymalną ścieżkę).<para/> /// Informacja, czy szukana ścieżka istnieje, zawsze jest zwracana poprawnie. /// Jeśli nie istnieje (wynik false), to parametr p jest równy null. /// </remarks> /// <seealso cref="AStarGraphExtender"/> /// <seealso cref="ASD.Graphs"/> public static bool AStar(this Graph g, int s, int t, out Edge[] p, Func <int, int, double> h = null) { bool Cmp(KeyValuePair <int, double> keyValuePair1, KeyValuePair <int, double> keyValuePair2) { return(keyValuePair1.Value != keyValuePair2.Value ? keyValuePair1.Value < keyValuePair2.Value : keyValuePair1.Key < keyValuePair2.Key); } var priorityQueue = new PriorityQueue <int, double>(Cmp, CMonDoSomething.Nothing); var hashSet = new HashSet <int>(); var hashTable = new HashTable <int, double>(CMonDoSomething.Nothing); var hashTable2 = new HashTable <int, Edge>(CMonDoSomething.Nothing); if (h == null) { h = (i, j) => 0.0; } p = null; priorityQueue.Put(s, 0.0); hashTable[s] = 0.0; hashTable2[s] = new Edge(s, s, 0.0); var num = -1; while (!priorityQueue.Empty) { num = priorityQueue.Get(); hashSet.Add(num); if (num == t) { break; } foreach (var edge in g.OutEdges(num)) { if (hashSet.Contains(edge.To)) { continue; } if (!priorityQueue.Contains(edge.To)) { priorityQueue.Put(edge.To, double.PositiveInfinity); hashTable[edge.To] = double.PositiveInfinity; } if (!(hashTable[edge.To] > hashTable[num] + edge.Weight)) { continue; } hashTable[edge.To] = hashTable[num] + edge.Weight; hashTable2[edge.To] = edge; priorityQueue.ImprovePriority(edge.To, hashTable[edge.To] + h(edge.To, t)); } } if (num != t) { return(false); } var edgesStack = new EdgesStack(); for (var num3 = t; num3 != s; num3 = hashTable2[num3].From) { edgesStack.Put(hashTable2[num3]); } p = edgesStack.ToArray(); return(true); }
/// <summary> /// Znajduje scieżkę Eulera w grafie /// </summary> /// <param name="g">Badany graf</param> /// <param name="ec">Znaleziona ścieżka (parametr wyjściowy)</param> /// <returns>Informacja czy ścieżka Eulera istnieje</returns> /// <remarks> /// Jeśli w badanym grafie nie istnieje ścieżka Eulera metoda zwraca false, /// parametr ec ma wówczas wartość null.<para/> /// Metoda nie modyfikuje badanego grafu.<para/> /// Metoda implementuje algorytm Fleury'ego. /// </remarks> /// <seealso cref="EulerPathGraphExtender"/> /// <seealso cref="ASD.Graphs"/> public static bool EulerPath(this Graph g, out Edge[] ec) { ec = null; var oddDegreeCounter = 0; var startVertex = 0; var hasOutGreaterThanIn = false; var hasInGreaterThanOut = false; if (g.Directed) { for (var i = 0; i < g.VerticesCount; i++) { var outDegree = g.OutDegree(i); var inDegree = g.InDegree(i); if (Math.Abs(outDegree - inDegree) > 1) { return(false); } if (outDegree > inDegree) { if (hasOutGreaterThanIn) { return(false); } startVertex = i; hasOutGreaterThanIn = true; } if (inDegree > outDegree) { if (hasInGreaterThanOut) { return(false); } hasInGreaterThanOut = true; } } } else { for (var i = 0; i < g.VerticesCount; i++) { if ((g.OutDegree(i) & 1) != 1) { continue; } startVertex = i; if (++oddDegreeCounter > 2) { return(false); } } } var visited = new bool[g.VerticesCount]; var graph = g.Clone(); var s1 = new EdgesStack(); var s2 = new EdgesStack(); s2.Put(new Edge(startVertex, startVertex)); while (!s2.Empty) { var vertex = s2.Peek().To; visited[vertex] = true; if (graph.OutDegree(vertex) > 0) { var edge = graph.OutEdges(vertex).First(); s2.Put(edge); graph.DelEdge(edge); } else { s1.Put(s2.Get()); } } s1.Get(); if (graph.EdgesCount > 0) { return(false); } for (var i = 0; i < g.VerticesCount; i++) { if (!visited[i]) { return(false); } } ec = s1.ToArray(); return(true); }