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