Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        /// <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>
        /// 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);
        }