/// <summary> /// Bada czy graf nieskierowany jest acykliczny /// </summary> /// <param name="g">Badany graf</param> /// <returns>Informacja czy graf jest acykliczny</returns> /// <remarks> /// Metoda uruchomiona dla grafu skierowanego zgłasza wyjątek <see cref="System.ArgumentException"/>. /// <br/> /// Graf wejściowy pozostaje niezmieniony. /// </remarks> public static bool IsUndirectedAcyclic(this Graph g) { if (g.Directed) { throw new System.ArgumentException("Graf jest skierowany"); } bool[] isVertexInCurrentPath = new bool[g.VerticesCount]; EdgesStack edgesInCurrentPath = new EdgesStack(); bool isAcyclic = g.GeneralSearchAll <EdgesStack>(v => { isVertexInCurrentPath[v] = true; return(true); }, v => { isVertexInCurrentPath[v] = false; return(true); }, e => { if (!edgesInCurrentPath.Empty && edgesInCurrentPath.Peek().From == e.To) { // Krawędź "powrotna" aktualnej ścieżki edgesInCurrentPath.Get(); return(true); } if (isVertexInCurrentPath[e.To]) { return(false); } edgesInCurrentPath.Put(e); return(true); }, out int cc); return(isAcyclic); }
/// <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 składowe dwuspójne /// </summary> /// <param name="g">Badany graf</param> /// <returns> /// Krotka (count, bcc, ap) składająca się z liczby składowych dwuspójnych, /// grafu opisującego te składowe i tablicy zawierającej punkty artykulacji /// </returns> /// <exception cref="ArgumentException">Gdy uruchomiona dla grafu skierowanego</exception> /// <remarks> /// Wagi krawędzi w grafie opisującym składowe dwuspójne (bcc) odpowiadają numerom tych składowych.<para/> /// Metoda uruchomiona dla grafu skierowanego zgłasza wyjątek ArgumentException. /// </remarks> /// <seealso cref="BiconnectedGraphExtender"/> /// <seealso cref="ASD.Graphs"/> public static (int count, Graph bcc, int[] ap) BiconnectedComponents(this Graph g) { if (g.Directed) { throw new ArgumentException("Directed graphs are not allowed"); } var bcc = g.IsolatedVerticesGraph(); var edgesStack = new EdgesStack(); var discovery = new int[g.VerticesCount]; var low = new int[g.VerticesCount]; var visited = new bool[g.VerticesCount]; var isArticulation = new bool[g.VerticesCount]; var count = 0; var time = 0; int GetArticulationPoints(int i, int d) { var children = 0; visited[i] = true; low[i] = discovery[i] = time++; foreach (var edge in g.OutEdges(i)) { edgesStack.Put(edge); if (!visited[edge.To]) { var ap = GetArticulationPoints(edge.To, d); if (low[i] > ap) { low[i] = ap; } if ((i == d || discovery[i] > ap) && i != d) { continue; } if (i != d || ++children > 1) { isArticulation[i] = true; } Edge e; do { e = edgesStack.Get(); bcc.AddEdge(e.From, e.To, count); }while (e.From != i); count++; } else if (low[i] > discovery[edge.To]) { low[i] = discovery[edge.To]; } } return(low[i]); } for (var i = 0; i < g.VerticesCount; i++) { if (!visited[i]) { GetArticulationPoints(i, i); } } var list = new List <int>(); for (var j = 0; j < g.VerticesCount; j++) { if (isArticulation[j]) { list.Add(j); } } return(count, bcc, list.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 //check if graph has euler cycle or path int numOfOddVertices = 0, cc = 0; int oddVertex = -1; Predicate <int> preVertex = delegate(int vertex) { if (g.OutDegree(vertex) % 2 != 0) { numOfOddVertices++; oddVertex = vertex; if (numOfOddVertices > 2) { return(false); } } return(true); }; GeneralSearchGraphExtender.GeneralSearchAll <EdgesStack>(g, preVertex, null, null, out cc); if (cc != 1 || numOfOddVertices > 2) { ec = null; return(false); } Graph h = g.Clone(); //find euler cycle //if(0 == numOfOddVertices) //{ EdgesStack euler = new EdgesStack(); EdgesStack tmp = new EdgesStack(); int v = -1 == oddVertex ? 0 : oddVertex; //h.OutDegree(0) > 0, if start with oddVertex algorithm finds euler path tmp.Put(new Edge(v, v)); //dummy edge to remove later while (!tmp.Empty) { v = tmp.Peek().To; if (h.OutDegree(v) > 0) { foreach (var e in h.OutEdges(v)) { tmp.Put(e); h.DelEdge(e); break; } } else { euler.Put(tmp.Get()); } } euler.Get(); //dummy edge ec = new Edge[euler.Count]; for (int i = 0; i < ec.Length; i++) { ec[i] = euler.Get(); } return(true); //} /* * 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) */ }
/// <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); }