예제 #1
0
        private EdgesStack FindPath(Graph g, int from, int to)
        {
            EdgesStack       edgesStack = new EdgesStack();
            Predicate <Edge> onNewEdge  = delegate(Edge e)
            {
                if (edgesStack.Empty || e.To != edgesStack.Peek().To)
                {
                    edgesStack.Put(new Edge(e.To, e.From));
                }
                return(true);
            };
            Predicate <int> onLeaving = delegate(int n)
            {
                if (!edgesStack.Empty)
                {
                    edgesStack.Get();
                }
                return(true);
            };
            Predicate <int> onEntering = delegate(int n)
            {
                return(n != to);
            };

            g.GeneralSearchFrom <EdgesStack>(from, onEntering, onLeaving, onNewEdge);

            return(edgesStack);
        }
예제 #2
0
        /// <summary>
        /// Podział grafu na cykle. Zakładamy, że dostajemy graf nieskierowany i wszystkie wierzchołki grafu mają parzyste stopnie
        /// (nie trzeba sprawdzać poprawności danych).
        /// </summary>
        /// <param name="G">Badany graf</param>
        /// <returns>Tablica cykli; krawędzie każdego cyklu powinny być uporządkowane zgodnie z kolejnością na cyklu, zaczynając od dowolnej</returns>
        /// <remarks>
        /// Metoda powinna działać w czasie O(m)
        /// </remarks>
        public static Edge[][] cyclePartition(this Graph G)
        {
            Graph gr = G.Clone();

            Edge[][]   eTable = new Edge[G.EdgesCount][];
            EdgesStack eStack = new EdgesStack();

            bool[] visited     = new bool[gr.VerticesCount];
            int    numOfCycles = 0;

            DeepSearch(ref gr, ref eStack, ref visited, ref eTable, ref numOfCycles);

            int notNull = 0;

            foreach (var x in eTable)
            {
                if (x == null)
                {
                    break;
                }
                else
                {
                    notNull++;
                }
            }
            Edge[][] resultTable = new Edge[notNull][];
            int      i           = 0;

            while (i < notNull)
            {
                resultTable[i] = eTable[i];
                i++;
            }
            return(resultTable);
        }
예제 #3
0
        /// <summary>
        /// Algorytm znajdujący drugą pod względem długości najkrótszą ścieżkę między a i b.
        /// Możliwe, że jej długość jest równa najkrótszej (jeśli są dwie najkrótsze ścieżki,
        /// algorytm zwróci jedną z nich).
        /// Wymagamy, aby na ścieżce nie było powtórzeń wierzchołków ani krawędzi.
        /// Można założyć, że a!=b oraz że w grafie nie występują pętle.
        /// </summary>
        /// <remarks>
        /// Wymagana złożoność to O(nD), gdzie D jest złożonością implementacji algorytmu Dijkstry w bibliotece Graph.
        /// </remarks>
        /// <param name="g"></param>
        /// <param name="path">null jeśli druga ścieżka nie istnieje, wpp ściezka jako ciąg krawędzi</param>
        /// <returns>null jeśli druga ścieżka nie istnieje, wpp długość tej ścieżki</returns>
        public static double?FindSecondSimpleShortestPath(this Graph g, int a, int b, out Edge[] path)
        {
            path = null;
            PathsInfo[] bestPathInfo, tempPathInfo, secondBestPathInfo = null;
            double      secondBest = double.PositiveInfinity;
            EdgesStack  stack      = new EdgesStack();

            if (!g.DijkstraShortestPaths(a, out bestPathInfo))
            {
                return(null);
            }
            int v         = b;
            int pathCount = 0;

            while (bestPathInfo[v].Last != null)
            {
                stack.Put((Edge)bestPathInfo[v].Last);
                v = stack.Peek().From;
                pathCount++;
            }
            Edge deleted;

            while (!stack.Empty)
            {
                deleted = stack.Get();
                g.DelEdge(deleted);
                g.DijkstraShortestPaths(a, out tempPathInfo);
                if (tempPathInfo[b].Dist < secondBest)
                {
                    secondBestPathInfo = tempPathInfo;
                    secondBest         = tempPathInfo[b].Dist;
                }
                g.AddEdge(deleted);
            }
            List <Edge> pathList = new List <Edge>();

            v = b;
            if (!double.IsPositiveInfinity(secondBest))
            {
                while (secondBestPathInfo[v].Last != null)
                {
                    pathList.Add((Edge)secondBestPathInfo[v].Last);
                    v = pathList.Last().From;
                }
                pathList.Reverse();
                path = pathList.ToArray();
            }
            if (path == null)
            {
                return(null);
            }
            else
            {
                return(pathList.Sum(edge => edge.Weight));
            }
        }
예제 #4
0
        // Część 4
        // Badanie czy graf nieskierowany jest acykliczny
        //   0.5 pkt
        // Parametry:
        //   g - badany graf
        // Wynik:
        //   true jeśli graf jest acykliczny, false jeśli graf nie jest acykliczny
        // Uwagi:
        //   1) Metoda uruchomiona dla grafu skierowanego powinna zgłaszać wyjątek Lab03Exception
        //   2) Graf wejściowy pozostaje niezmieniony
        //   3) Najpierw pomysleć jaki, prosty do sprawdzenia, warunek spełnia acykliczny graf nieskierowany
        //      Zakodowanie tefo sprawdzenia nie powinno zająć więcej niż kilka linii!
        //      Zadanie jest bardzo łatwe (jeśli wydaje się trudne - poszukać prostszego sposobu, a nie walczyć z trudnym!)
        public static bool Lab03IsUndirectedAcyclic(this Graph g)
        {
            if (g.Directed)
            {
                throw new Lab03Exception();
            }

            EdgesStack edgesToVisit = new EdgesStack();

            bool[] wasVisited = new bool[g.VerticesCount];
            for (int i = 0; i < g.VerticesCount; i++)
            {
                if (wasVisited[i])
                {
                    continue;
                }

                wasVisited[i] = true;
                foreach (Edge e in g.OutEdges(i))
                {
                    edgesToVisit.Put(e);
                }

                while (!edgesToVisit.Empty)
                {
                    Edge e = edgesToVisit.Get();
                    if (wasVisited[e.To])
                    {
                        return(false);
                    }

                    wasVisited[e.To] = true;
                    foreach (Edge e2 in g.OutEdges(e.To))
                    {
                        if (e2.To == e.From)
                        {
                            continue;
                        }

                        edgesToVisit.Put(e2);
                    }
                }
            }

            return(true);
        }
예제 #5
0
        public static void DeepSearch(ref Graph G, ref EdgesStack eStack, ref bool[] visited, ref Edge[][] eTable, ref int numOfCycles)
        {
            Stack <int> vStack;
            int         lastv = -1;

            for (int s = 0; s < G.VerticesCount; s++)
            {
                vStack = new Stack <int>();
                while (G.OutDegree(s) > 0)
                {
                    if (vStack.Count == 0)
                    {
                        vStack.Push(s);
                    }
                    int v = vStack.Peek();
                    if (G.OutDegree(v) == 0)
                    {
                        break;
                    }
                    if (visited[v])
                    {
                        int i = 0; Edge temp; EdgesStack tempStack = new EdgesStack();
                        if (eStack.Count == 1)
                        {
                            temp = eStack.Get();
                            vStack.Pop();
                            G.DelEdge(temp);
                            tempStack.Put(temp);
                            i++;
                        }
                        else
                        {
                            do
                            {
                                temp = eStack.Get();
                                vStack.Pop();
                                G.DelEdge(temp);
                                visited[temp.From] = false;
                                tempStack.Put(temp);
                                i++;
                            } while (temp.From != v);
                            if (eStack.Count != 0)
                            {
                                lastv = eStack.Peek().From;
                            }
                        }
                        eTable[numOfCycles] = new Edge[i];
                        i = 0;
                        while (!tempStack.Empty)
                        {
                            eTable[numOfCycles][i++] = tempStack.Get();
                        }
                        numOfCycles++;
                        continue;
                    }
                    else
                    {
                        visited[v] = true;
                        foreach (var e in G.OutEdges(v))
                        {
                            if (e.To != lastv)
                            {
                                vStack.Push(e.To);
                                eStack.Put(e);
                                break;
                            }
                        }
                        lastv = v;
                    }
                }
            }
        }
예제 #6
0
        /// <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>Długość ścieżki (jeśli nie istnieje to NaN)</returns>
        /// <remarks>
        /// Domyślna wartość parametru <i>h</i> (<b>null</b>) oznacza, że zostanie przyjęte oszacowanie zerowe.
        /// Algorytm A* sprowadza się wówczas do algorytmu Dijkstry.<br/>
        /// <br/>
        /// 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ę).<br/>
        /// Informacja, czy szukana ścieżka istnieje, zawsze jest zwracana poprawnie.
        /// Jeśli ścieżka nie istnieje (wynik <b>NaN</b>), to parametr <i>p</i> również jest równy <b>null</b>.
        /// </remarks>
        public static double AStar(this Graph g, int s, int t, out Edge[] p, System.Collections.Generic.Dictionary <int, string> description, System.Func <int, int, double> h = null)
        {
            var open  = new PriorityQueue <int, double>((x, y) => x.Value < y.Value, Graph.Access);
            var close = new System.Collections.Generic.HashSet <int>();  // dodać referencję system.dll
            var dist  = new HashTable <int, double>(Graph.Access);
            var last  = new HashTable <int, Edge>(Graph.Access);

            if (h == null)
            {
                h = (x, y) => 0;
            }
            int n = g.VerticesCount;

            double[] approximateDistances = new double[n];

            for (int i = 0; i < n; i++)
            {
                approximateDistances[i] = double.NaN;
                dist[i] = double.PositiveInfinity;
            }



            // Rozpoczęcie algorytmu przez dodanie wierzchołka startowego
            // (nie liczymy oszacowania odległości, bo to tylko niepotrzebna operacja w tym przypadku -
            // zawsze zaczniemy od startowego)
            approximateDistances[s] = 0;
            open.Put(s, 0);
            dist[s] = 0;

            while (!open.Empty)
            {
                int v = open.Get();
                close.Add(v);
                if (v == t)
                {
                    break;
                }

                foreach (Edge e in g.OutEdges(v))
                {
                    // Nie wracamy do już ustalonych wierzchołków
                    if (close.Contains(e.To))
                    {
                        continue;
                    }

                    // Sprawdzamy czy mamy lepszą odległość od źródła do danego wierzchołka
                    double prospectiveDistance = dist[v] + e.Weight;
                    if (dist[e.To] > prospectiveDistance)
                    {
                        dist[e.To] = prospectiveDistance;
                        last[e.To] = e;
                        if (approximateDistances[e.To].IsNaN())
                        {
                            approximateDistances[e.To] = h(e.To, t);
                        }
                        double newPriority = approximateDistances[e.To] + dist[e.To];
                        if (open.Contains(e.To))
                        {
                            open.ImprovePriority(e.To, newPriority);
                        }
                        else
                        {
                            open.Put(e.To, newPriority);
                        }
                    }
                }
            }

            foreach (int v in close)
            {
                description[v] = "close";
            }
            while (!open.Empty)
            {
                description[open.Get()] = "open";
            }

            if (double.IsPositiveInfinity(dist[t]))
            {
                p = null;
                return(double.NaN);
            }

            EdgesStack path     = new EdgesStack();
            int        currentV = t;

            while (currentV != s)
            {
                Edge e = last[currentV];
                path.Put(e);
                currentV = e.From;
            }

            p = path.ToArray();
            return(dist[t]);
        }
        /// <summary>
        /// Podział grafu na cykle. Zakładamy, że dostajemy graf nieskierowany i wszystkie wierzchołki grafu mają parzyste stopnie
        /// (nie trzeba sprawdzać poprawności danych).
        /// </summary>
        /// <param name="G">Badany graf</param>
        /// <returns>Tablica cykli; krawędzie każdego cyklu powinny być uporządkowane zgodnie z kolejnością na cyklu, zaczynając od dowolnej</returns>
        /// <remarks>
        /// Metoda powinna działać w czasie O(m)
        /// </remarks>
        public static Edge[][] cyclePartition(this Graph G)
        {
            List <Edge[]> cycles = new List <Edge[]>();
            Graph         h      = G.Clone();

            bool[]     visited    = new bool[h.VerticesCount];
            EdgesStack edges      = new EdgesStack();
            int        lastVertex = -1;

            while (h.EdgesCount > 0)
            {
                // Jesli zaczynamy szukac nowy cykl to:
                // - znajdz dowolny wierzcholek ktory ma jakies krawedzie
                // Wpp kontynuujemy z lastVertex
                int v = lastVertex;
                if (v == -1)
                {
                    visited = new bool[h.VerticesCount];
                    edges   = new EdgesStack();

                    for (int i = 0; i < h.VerticesCount; i++)
                    {
                        if (h.OutDegree(i) > 0)
                        {
                            v = i;
                            break;
                        }
                    }
                }

                // v - wierzcholek, ktory ma co najmniej 1 krawedz
                // Wezmy pierwsza krawedz
                visited[v] = true;
                Edge edge;

                foreach (Edge e in h.OutEdges(v))   //TODO: WHY FOREACH?
                {
                    // Usuwamy z grafu pierwsza krawedz i wrzucamy na stos
                    h.DelEdge(e);
                    edges.Put(e);

                    // Napotkalismy cykl
                    if (visited[e.To])
                    {
                        Edge[] cycle     = new Edge[edges.Count];
                        Edge   firstEdge = edges.Get();
                        int    i         = 0;
                        cycle[i++] = firstEdge;

                        while (!edges.Empty)
                        {
                            Edge e2 = edges.Get();
                            cycle[i++]       = e2;
                            visited[e2.From] = visited[e2.To] = false;

                            if (e2.From == firstEdge.To)
                            {
                                break;
                            }
                        }

                        Array.Resize(ref cycle, i);
                        Array.Reverse(cycle);
                        cycles.Add(cycle);

                        // Czy wierzcholek na ktorym skonczylismy ma jeszcze jakies krawedzie
                        if (h.OutDegree(e.To) > 0)
                        {
                            lastVertex = e.To;
                        }
                        else
                        {
                            lastVertex = -1;
                        }
                    }
                    else
                    {
                        lastVertex = e.To;
                    }

                    break;
                }
            }

            Edge[][] ret   = new Edge[cycles.Count][];
            int      count = cycles.Count;

            for (int i = 0; i < count; i++)
            {
                ret[i] = cycles.Last();
                cycles.RemoveAt(cycles.Count - 1);
            }
            return(ret);

            //TODO: find the efficient method
            //Graph g = G.Clone();
            //Stack<Edge[]> cycles = new Stack<Edge[]>();
            //Edge[] cycle;

            //while(FindCycle(g, out cycle))
            //{
            //    cycles.Push(cycle);

            //    foreach (var e in cycle)
            //    {
            //        g.DelEdge(e);
            //    }
            //}

            //Edge[][] result = new Edge[cycles.Count][];

            //int i = 0;
            //while(cycles.Count > 0)
            //{
            //    result[i++] = cycles.Pop();
            //}

            //return result;
        }
        public static bool FindCycle(this Graph g, out Edge[] cycle)
        {
            int[]      visited = new int[g.VerticesCount]; // 0 - nieodwiedzony, 1 - szary, 2 - czarny
            int[]      from    = new int[g.VerticesCount];
            EdgesStack edges   = new EdgesStack();

            cycle = new Edge[g.VerticesCount];
            bool hasCycle = false;
            int  cycleEnd = -1;
            int  cc;

            Predicate <int> preVertex = delegate(int v)
            {
                visited[v] = 1; // szary
                return(true);
            };

            Predicate <int> postVertex = delegate(int v)
            {
                visited[v] = 2; // czarny

                if (!edges.Empty)
                {
                    edges.Get();
                }

                return(true);
            };

            Predicate <Edge> visitEdge = delegate(Edge e)
            {
                if (!g.Directed && from[e.From] == e.To)
                {
                    return(true);
                }

                from[e.To] = e.From;
                edges.Put(e);

                if (visited[e.To] == 1)
                {
                    hasCycle = true;
                    cycleEnd = e.To;
                    return(false);
                }

                return(true);
            };

            g.GeneralSearchAll <EdgesStack>(preVertex, postVertex, visitEdge, out cc);

            if (hasCycle)
            {
                int  i    = 0;
                bool stop = false;

                while (!edges.Empty)
                {
                    Edge e = edges.Get();

                    if (!stop)
                    {
                        cycle[i++] = e;
                    }

                    if (!edges.Empty && edges.Peek().To == cycleEnd)
                    {
                        stop = true;
                        continue;
                    }
                }

                Array.Resize <Edge>(ref cycle, i);
                Array.Reverse(cycle);

                return(true);
            }

            cycle = null;
            return(false);
        }