Exemple #1
0
        //uwagi do wszystkich części (graf najkrótszych ścieżek)
        //   Jeżeli nie ma ścieżki pomiędzy miastami A i B to tworzymy sztuczną krawędź od A do B o karnym koszcie 10 000.

        // return: tablica kosztów organizacji ŚDM dla poszczególnym miast gdzie
        // za koszt organizacji ŚDM uznajemy sumę kosztów dostania się ze wszystkim miast do danego miasta, bez uwzględnienia kosztów przechodzenia przez miasta.
        // minCost: najmniejszy koszt
        // paths: graf skierowany zawierający drzewo najkrótyszch scieżek od wszyskich miast do miasta organizującego ŚDM (miasta z najmniejszym kosztem organizacji).
        public int[] FindBestLocationWithoutCityCosts(out int minCost, out Graph paths)
        {
            //graphExport.Export(RoadsGraph);
            int tmpCost = 0;

            PathsInfo[][] pathsInfos = new PathsInfo[RoadsGraph.VerticesCount][];    //pathsInfos[v] -> PathsInfo from vertex v to every other vertex
            minCost = Int32.MaxValue;
            int[] forEachCityCosts = new int[RoadsGraph.VerticesCount];
            Graph shortestPaths    = RoadsGraph.IsolatedVerticesGraph(true, RoadsGraph.VerticesCount);
            int   minVertex        = -1;

            //calculate minimal cost
            for (int v = 0; v < RoadsGraph.VerticesCount; v++)
            {
                RoadsGraph.DijkstraShortestPaths(v, out pathsInfos[v]);

                for (int i = 0; i < pathsInfos.Length; i++)
                {   //if there is no connection, add connection of cost noEdgePenalty
                    tmpCost += double.IsNaN(pathsInfos[v][i].Dist) ? noEdgePenalty : (int)pathsInfos[v][i].Dist;
                }

                forEachCityCosts[v] = tmpCost;

                if (minCost > tmpCost)
                {
                    minCost   = tmpCost;
                    minVertex = v;
                    //minVertexPathsInfos = pathsInfos;
                }

                tmpCost = 0;
            }

            //construct paths from all cities to minimal cost city
            for (int v = 0; v < RoadsGraph.VerticesCount; v++)
            {
                if (v == minVertex)
                {
                    continue;
                }

                Edge[] path = PathsInfo.ConstructPath(v, minVertex, pathsInfos[v]);

                //if there is no connection, add connection of cost noEdgePenalty
                if (null == path)
                {
                    shortestPaths.AddEdge(v, minVertex, noEdgePenalty);
                }
                else
                {
                    foreach (var e in path)
                    {
                        shortestPaths.AddEdge(e);
                    }
                }
            }

            paths = shortestPaths;
            return(forEachCityCosts);
        }
Exemple #2
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[] d, best = null;
            double      min     = Double.MaxValue;

            g.DijkstraShortestPaths(a, out d);
            if (d[b].Dist.IsNaN())
            {
                return(null);
            }
            Edge[] firstpath = PathsInfo.ConstructPath(a, b, d);

            foreach (Edge e in firstpath)
            {
                g.DelEdge(e);
                g.DijkstraShortestPaths(a, out d);
                if (d[b].Dist < min)
                {
                    min  = d[b].Dist;
                    best = d;
                }
                g.AddEdge(e);
            }

            if (min == Double.MaxValue)
            {
                return(null);
            }

            path = PathsInfo.ConstructPath(a, b, best);

            return(min);
        }
Exemple #3
0
        /// <summary>
        /// Sprawdza możliwość przejazdu między dzielnicami-wielokątami district1 i district2,
        /// tzn. istnieją para ulic, pomiędzy którymi jest przejazd
        /// oraz fragment jednej ulicy należy do obszaru jednej z dzielnic i fragment drugiej należy do obszaru drugiej dzielnicy
        /// </summary>
        /// <returns>Informacja czy istnieje przejazd między dzielnicami</returns>
        public bool CheckDistricts(Street[] streets, Point[] district1, Point[] district2, out List <int> path, out List <Point> intersections)
        {
            AdjacencyListsGraph <SimpleAdjacencyList> g = new AdjacencyListsGraph <SimpleAdjacencyList>(false, streets.Length + 2);

            path          = new List <int>();
            intersections = new List <Point>();

            int s  = streets.Length;
            int d1 = streets.Length + 1;
            int d2 = streets.Length;

            //Construct graph
            for (int i = 0; i < s; i++)
            {
                for (int j = 0; j < district1.Length; j++)
                {
                    Street temp = new Street(district1[j], district1[(j + 1) % district1.Length]);
                    if (CheckIntersection(temp, streets[i]) == 1)
                    {
                        g.AddEdge(i, d1);
                    }
                }

                for (int j = 0; j < district2.Length; j++)
                {
                    Street temp = new Street(district2[j], district2[(j + 1) % district2.Length]);
                    if (CheckIntersection(temp, streets[i]) == 1)
                    {
                        g.AddEdge(i, d2);
                    }
                }

                for (int j = i + 1; j < s; j++)
                {
                    if (CheckIntersection(streets[i], streets[j]) == 1)
                    {
                        g.AddEdge(i, j);
                    }
                }
            }

            PathsInfo[] d = new PathsInfo[s + 2];
            g.DijkstraShortestPaths(d1, out d);
            if (double.IsNaN(d[d2].Dist))
            {
                return(false);
            }

            Edge[] edges = PathsInfo.ConstructPath(d1, d2, d);
            for (int i = 0; i < edges.Length - 1; i++)
            {
                path.Add(edges[i].To);
                if (i > 0)
                {
                    intersections.Add(GetIntersectionPoint(streets[edges[i].From], streets[edges[i].To]));
                }
            }
            return(true);
        }
Exemple #4
0
        /// <summary>
        /// Wersja III i IV zadania
        /// Zwraca najkrótszy możliwy czas przejścia przez labirynt z użyciem co najwyżej k lasek dynamitu
        /// </summary>
        /// <param name="maze">labirynt</param>
        /// <param name="k">liczba dostępnych lasek dynamitu, dla wersji III k=1</param>
        /// <param name="path">zwracana ścieżka</param>
        /// <param name="t">czas zburzenia ściany</param>
        /// // pomysl: k+1 takich samych grafow(warstw) bez krawedzi X , a krawedzie X to takie "mosty" miedzy warstwami
        // ETAP 3 i 4
        public int FindShortestPathWithKDynamites(char[,] maze, int k, out string path, int t)
        {
            path = "";

            int X     = maze.GetLength(1);
            int Y     = maze.GetLength(0);
            int n     = X * Y; // liczba punktow w tablicy, dla ulatwienia w szukaniu numeru wierzcholka w innej warstwie grafu
            int start = -1;
            int end   = -1;
            AdjacencyListsGraph <AVLAdjacencyList> g = new AdjacencyListsGraph <AVLAdjacencyList>(true, (k + 1) * n);

            PathsInfo[] p = null;
            createGraph(maze, g, t, out start, out end, k, n);
            ShortestPathsGraphExtender.DijkstraShortestPaths(g, start, out p);
            int[] dist = new int[k + 1]; // tablica najlepszych drog dla uzycia dynamitow od 0 do k
            for (int i = 0; i <= k; ++i)
            {
                dist[i] = -1;
            }
            int min   = int.MaxValue;
            int index = 0;               // ilosc dynamitow zuzytych dla najlepszej drogi

            for (int i = 0; i <= k; ++i) // sprawdzenie dla kazdej ilosci uzytego dynamitu najlepszej drogi
            {
                int tmp = (int)p[end + i * n].Dist;
                if (!Double.IsNaN(p[end + i * n].Dist)) // jesli nie NaN to porownac z wartoscia najmniejsza
                {
                    dist[i] = tmp;
                    if (tmp < min) // jesli nowa wartosc lepsza to zapisac jako min
                    {
                        min   = tmp;
                        index = i;
                    }
                }
            }
            if (min == int.MaxValue)
            {
                return(-1); // jesli nie znaleziono sciezki to -1
            }
            else
            {
                if (X > 1)
                {
                    path = constructStringE34(PathsInfo.ConstructPath(start, end + index * n, p), X, n);
                }
                else // jesli kolejne wierzcholki grafu nie sa na tablicy po prawo/lewo, tylko gora/dol (bo wymiar 1xN czy Nx1 nie wiem)
                {
                    path = constructStringE341xN(PathsInfo.ConstructPath(start, end + index * n, p), X, n);
                }
                return(min);
            }
        }
        /// <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)
        {
            PathsInfo[] pi;
            PathsInfo[] pi2;
            Graph       G = g.Clone();

            G.DijkstraShortestPaths(a, out pi);

            if (double.IsNaN(pi[b].Dist))
            {
                path = null;
                return(null);
            }

            Edge[] firstPath = PathsInfo.ConstructPath(a, b, pi);

            double secondShortest = double.PositiveInfinity;

            path = null;

            for (int i = firstPath.Length - 1; i >= 0; i--)
            {
                G.DelEdge(firstPath[i]);

                G.DijkstraShortestPaths(a, out pi2);
                if (double.IsNaN(pi2[b].Dist))
                {
                    continue;
                }

                if (pi2[b].Dist < secondShortest)
                {
                    secondShortest = pi2[b].Dist;
                    path           = PathsInfo.ConstructPath(a, b, pi2);
                }

                G.AddEdge(firstPath[i]);
            }

            if (secondShortest == double.PositiveInfinity)
            {
                return(null);
            }

            return(secondShortest);
        }
Exemple #6
0
        // ETAP 1 i 2
        public int FindShortestPath(char[,] maze, bool withDynamite, out string path, int t = 0)
        {
            path = "";
            int X = maze.GetLength(1);
            int Y = maze.GetLength(0);

            int start = -1;
            int end   = -1;
            AdjacencyListsGraph <AVLAdjacencyList> g = new AdjacencyListsGraph <AVLAdjacencyList>(true, X * Y);

            PathsInfo[] p = null;

            if (t == 0)
            {
                createGraph(maze, g, out start, out end);
            }
            else
            {
                createGraph(maze, g, t, out start, out end);
            }
            ShortestPathsGraphExtender.DijkstraShortestPaths(g, start, out p);
            int dist = (int)p[end].Dist;

            if (!Double.IsNaN(p[end].Dist))
            {
                if (X > 1)
                {
                    path = constructString(PathsInfo.ConstructPath(start, end, p));
                }
                else
                {
                    path = constructString1xN(PathsInfo.ConstructPath(start, end, p));
                }
                return(dist);
            }
            else
            {
                return(-1);
            }
        }
        /// <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)
        {
            PathsInfo[] d;
            g.DijkstraShortestPaths(a, out d);
            Edge[] shortestPath = PathsInfo.ConstructPath(a, b, d);
            if (shortestPath == null)
            {
                path = null;
                return(null);
            }
            double minDist = double.MaxValue;
            bool   changed = false;

            Edge[] temp = null;
            foreach (Edge e in shortestPath)
            {
                PathsInfo[] dT;
                Graph       tG = g.Clone();
                tG.DelEdge(e);
                tG.DijkstraShortestPaths(a, out dT);
                Edge[] secondShortest = PathsInfo.ConstructPath(a, b, dT);
                if (dT[b].Dist <= minDist)
                {
                    changed = true;
                    minDist = dT[b].Dist;
                    temp    = PathsInfo.ConstructPath(a, b, dT);
                }
            }
            if (!changed)
            {
                path = null;
                return(null);
            }
            path = temp;
            return(minDist);
        }
        /// <summary>
        /// Wersje zadania I oraz II
        /// Zwraca najkrótszy możliwy czas przejścia przez labirynt bez dynamitów lub z dowolną ich liczbą
        /// </summary>
        /// <param name="maze">labirynt</param>
        /// <param name="withDynamite">informacja, czy dostępne są dynamity
        /// Wersja I zadania -> withDynamites = false, Wersja II zadania -> withDynamites = true</param>
        /// <param name="path">zwracana ścieżka</param>
        /// <param name="t">czas zburzenia ściany (dotyczy tylko wersji II)</param>
        public int FindShortestPath(char[,] maze, bool withDynamite, out string path, int t = 0)
        {
            length = maze.GetLength(0);
            width  = maze.GetLength(1);

            int nVertices = length * width;
            int start = 0, end = 0;

            Graph g = new AdjacencyListsGraph <AVLAdjacencyList>(true, nVertices);

            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    int v = ij2v(i, j);

                    if (maze[i, j] == 'S')
                    {
                        start = v;
                    }
                    if (maze[i, j] == 'E')
                    {
                        end = v;
                    }

                    if (withDynamite)
                    {
                        if (i + 1 < length && maze[i + 1, j] != 'X')
                        {
                            g.AddEdge(v, ij2v(i + 1, j), 1);
                        }
                        else if (i + 1 < length)
                        {
                            g.AddEdge(v, ij2v(i + 1, j), t);
                        }
                        if (j + 1 < width && maze[i, j + 1] != 'X')
                        {
                            g.AddEdge(v, ij2v(i, j + 1), 1);
                        }
                        else if (j + 1 < width)
                        {
                            g.AddEdge(v, ij2v(i, j + 1), t);
                        }
                        if (i - 1 >= 0 && maze[i - 1, j] != 'X')
                        {
                            g.AddEdge(v, ij2v(i - 1, j), 1);
                        }
                        else if (i - 1 >= 0)
                        {
                            g.AddEdge(v, ij2v(i - 1, j), t);
                        }
                        if (j - 1 >= 0 && maze[i, j - 1] != 'X')
                        {
                            g.AddEdge(v, ij2v(i, j - 1), 1);
                        }
                        else if (j - 1 >= 0)
                        {
                            g.AddEdge(v, ij2v(i, j - 1), t);
                        }
                    }
                    else
                    {
                        if (maze[i, j] != 'X')
                        {
                            if (i + 1 < length && maze[i + 1, j] != 'X')
                            {
                                g.AddEdge(v, ij2v(i + 1, j), 1);
                                g.AddEdge(ij2v(i + 1, j), v, 1);
                            }
                            if (j + 1 < width && maze[i, j + 1] != 'X')
                            {
                                g.AddEdge(ij2v(i, j + 1), v, 1);
                                g.AddEdge(v, ij2v(i, j + 1), 1);
                            }
                        }
                    }
                }
            }

            g.DijkstraShortestPaths(start, out PathsInfo[] d);

            if ((int)d[end].Dist == int.MinValue)
            {
                path = "";
                return(-1);
            }

            Edge[] pathEdges = PathsInfo.ConstructPath(start, end, d);

            StringBuilder builder = new StringBuilder();

            (int x, int y) = v2ij(pathEdges[0].From);
            foreach (var e in pathEdges)
            {
                (int xEnd, int yEnd) = v2ij(e.To);
                if (xEnd == x + 1)
                {
                    builder.Append('S');
                }
                if (xEnd == x - 1)
                {
                    builder.Append('N');
                }
                if (yEnd == y + 1)
                {
                    builder.Append('E');
                }
                if (yEnd == y - 1)
                {
                    builder.Append('W');
                }
                x = xEnd;
                y = yEnd;
            }

            path = builder.ToString(); // tej linii na laboratorium nie zmieniamy!
            return((int)d[end].Dist);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="taskGraph">Graf opisujący zależności procedur</param>
        /// <param name="taskTimes">Tablica długości czasów procedur</param>
        /// <param name="startTimes">Parametr wyjśćiowy z najpóźniejszymi możliwymi startami procedur przy optymalnym czasie całości</param>
        /// <param name="startTimes">Parametr wyjśćiowy z dowolna wybraną ścieżką krytyczną</param>
        /// <returns>Najkrótszy czas w jakim można wykonać cały program</returns>
        public double CalculateTimesLatestPossible(Graph taskGraph, double[] taskTimes, out double[] startTimes, out int[] criticalPath)
        {
            startTimes   = null;
            criticalPath = null;

            int n = taskGraph.VerticesCount;

            bool   allIsolated = true;
            int    maxV        = 0;
            double maxVal      = 0;

            for (int i = 0; i < n; i++)
            {
                if (taskGraph.OutEdges(i).Count() > 0)
                {
                    allIsolated = false;
                    break;
                }
                if (maxVal < taskTimes[i])
                {
                    maxV   = i;
                    maxVal = taskTimes[i];
                }
            }

            if (allIsolated)
            {
                startTimes = new double[n];
                for (int i = 0; i < n; i++)
                {
                    startTimes[i] = maxVal - taskTimes[i];
                }

                criticalPath = new int[] { maxV };

                return(maxVal);
            }

            var startingVertices = new List <int>();

            for (int i = 0; i < n; i++)
            {
                if (taskGraph.InDegree(i) == 0)
                {
                    startingVertices.Add(i);
                }
            }

            var endingVertices = new List <int>();

            for (int i = 0; i < n; i++)
            {
                if (taskGraph.OutDegree(i) == 0)
                {
                    endingVertices.Add(i);
                }
            }

            var reversedGraph = taskGraph.Reverse();

            Graph g = taskGraph.IsolatedVerticesGraph(true, n + 2);


            for (int i = 0; i < n; i++)
            {
                foreach (var v in reversedGraph.OutEdges(i))
                {
                    g.AddEdge(i, v.To, -taskTimes[i]);
                }
            }

            //n - zrodlo
            //n+1 ujscie

            foreach (var i in endingVertices)
            {
                g.AddEdge(n, i, 0);
            }

            foreach (var i in startingVertices)
            {
                g.AddEdge(i, n + 1, -taskTimes[i]);
            }


            g.DAGShortestPaths(n, out PathsInfo[] d);
            double programTime = -d[n + 1].Dist;

            startTimes = new double[n];

            for (int i = 0; i < n; i++)
            {
                startTimes[i] = programTime + d[i].Dist - taskTimes[i];
            }

            int startigVertexForCriticalPath = 0;

            var longestPath = PathsInfo.ConstructPath(n, n + 1, d);

            startigVertexForCriticalPath = longestPath[longestPath.Length - 1].From;


            Edge[] path = PathsInfo.ConstructPath(n, startigVertexForCriticalPath, d);


            criticalPath = new int[path.Length];


            for (int i = 0; i < criticalPath.Length; i++)
            {
                criticalPath[i] = path[i].To;
            }

            Array.Reverse(criticalPath);


            return(-d[n + 1].Dist);
        }
Exemple #10
0
        /// <summary>
        /// Wersje zadania I oraz II
        /// Zwraca najkrótszy możliwy czas przejścia przez labirynt bez dynamitów lub z dowolną ich liczbą
        /// </summary>
        /// <param name="maze">labirynt</param>
        /// <param name="withDynamite">informacja, czy dostępne są dynamity
        /// Wersja I zadania -> withDynamites = false, Wersja II zadania -> withDynamites = true</param>
        /// <param name="path">zwracana ścieżka</param>
        /// <param name="t">czas zburzenia ściany (dotyczy tylko wersji II)</param>
        public int FindShortestPath(char[,] maze, bool withDynamite, out string path, int t = 0)
        {
            //path = null; // tej linii na laboratorium nie zmieniamy!

            int            totalRows    = maze.GetLength(0);
            int            totalColumns = maze.GetLength(1);
            int            totalFields  = totalRows * totalColumns;
            int            startVertex  = -1;
            int            endVertex    = -1;
            HashSet <char> goodChars    = new HashSet <char>()
            {
                'O', 'S', 'E'
            };
            Graph g = new AdjacencyListsGraph <HashTableAdjacencyList>(true, totalFields);

            for (int row = 0; row < totalRows; row++)
            {
                for (int column = 0; column < totalColumns; column++)
                {
                    //if (maze[row, column] == 'X')
                    //    continue;
                    if (maze[row, column] == 'S')
                    {
                        startVertex = GetVertexNumber(row, column);
                    }
                    if (maze[row, column] == 'E')
                    {
                        endVertex = GetVertexNumber(row, column);
                    }
                    int currentVertexNumber = GetVertexNumber(row, column);
                    if (row > 0)
                    {
                        int otherVertexNumber = GetVertexNumber(row - 1, column);
                        if (goodChars.Contains(maze[row - 1, column]))
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber);
                        }
                        if (maze[row - 1, column] == 'X' && t != 0)
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber, t);
                        }
                    }
                    if (row < totalRows - 1)
                    {
                        int otherVertexNumber = GetVertexNumber(row + 1, column);
                        if (goodChars.Contains(maze[row + 1, column]))
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber);
                        }
                        if (maze[row + 1, column] == 'X' && t != 0)
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber, t);
                        }
                    }
                    if (column > 0)
                    {
                        int otherVertexNumber = GetVertexNumber(row, column - 1);
                        if (goodChars.Contains(maze[row, column - 1]))
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber);
                        }
                        if (maze[row, column - 1] == 'X' && t != 0)
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber, t);
                        }
                    }
                    if (column < totalColumns - 1)
                    {
                        int otherVertexNumber = GetVertexNumber(row, column + 1);
                        if (goodChars.Contains(maze[row, column + 1]))
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber);
                        }
                        if (maze[row, column + 1] == 'X' && t != 0)
                        {
                            g.AddEdge(currentVertexNumber, otherVertexNumber, t);
                        }
                    }
                }
            }

            bool result = g.DijkstraShortestPaths(startVertex, out PathsInfo[] pathsInfo);

            double length = pathsInfo[endVertex].Dist;

            if (double.IsNaN(length))
            {
                path = "";
                return(-1);
            }
            else
            {
                Edge[] pathEdges = PathsInfo.ConstructPath(startVertex, endVertex, pathsInfo);

                StringBuilder pathStringBuilder = new StringBuilder();
                foreach (var edge in pathEdges)
                {
                    pathStringBuilder.Append(ConvertEdgeToChar(edge));
                }

                path = pathStringBuilder.ToString();
                return((int)length);
            }

            //--------------------------------------------------------
            int GetVertexNumber(int row, int column)
            {
                return(row * totalColumns + column);
            }

            char ConvertEdgeToChar(Edge edge)
            {
                var startField = GetRowAndColumn(edge.From);
                var endField   = GetRowAndColumn(edge.To);

                if (startField.row == endField.row)
                {
                    if (endField.column > startField.column)
                    {
                        return('E');
                    }
                    else if (endField.column < startField.column)
                    {
                        return('W');
                    }
                }
                else if (startField.column == endField.column)
                {
                    if (endField.row > startField.row)
                    {
                        return('S');
                    }
                    else if (endField.row < startField.row)
                    {
                        return('N');
                    }
                }
                throw new ArgumentException("Incorrect edge");
            }

            Field GetRowAndColumn(int vertexNumber)
            {
                int row    = vertexNumber / totalColumns;
                int column = vertexNumber - row * totalColumns;

                return(new Field(row, column));
            }
        }
Exemple #11
0
        /// <summary>
        /// Wersja III i IV zadania
        /// Zwraca najkrótszy możliwy czas przejścia przez labirynt z użyciem co najwyżej k lasek dynamitu
        /// </summary>
        /// <param name="maze">labirynt</param>
        /// <param name="k">liczba dostępnych lasek dynamitu, dla wersji III k=1</param>
        /// <param name="path">zwracana ścieżka</param>
        /// <param name="t">czas zburzenia ściany</param>
        public int FindShortestPathWithKDynamites(char[,] maze, int k, out string path, int t)
        {
            path = ""; // tej linii na laboratorium nie zmieniamy!

            int totalRows    = maze.GetLength(0);
            int totalColumns = maze.GetLength(1);
            int totalFields  = totalRows * totalColumns;

            int[] startVerices = new int[k + 1];
            int[] endVertices  = new int[k + 1];
            for (int i = 0; i < startVerices.Length; i++)
            {
                startVerices[i] = endVertices[i] = -1;
            }

            HashSet <char> goodChars = new HashSet <char>()
            {
                'O', 'S', 'E'
            };
            Graph g = new AdjacencyListsGraph <HashTableAdjacencyList>(true, totalFields * (k + 1));

            for (int row = 0; row < totalRows; row++)
            {
                for (int column = 0; column < totalColumns; column++)
                {
                    if (maze[row, column] == 'S')
                    {
                        for (int layerNumber = 0; layerNumber < startVerices.Length; layerNumber++)
                        {
                            startVerices[layerNumber] = GetVertexNumber(row, column, layerNumber);
                        }
                    }

                    if (maze[row, column] == 'E')
                    {
                        for (int layerNumber = 0; layerNumber < endVertices.Length; layerNumber++)
                        {
                            endVertices[layerNumber] = GetVertexNumber(row, column, layerNumber);
                        }
                    }

                    int[] currentVerticesNumbers = new int[k + 1];
                    int[] otherVerticesNumbers   = new int[k + 1];
                    for (int layerNumber = 0; layerNumber < currentVerticesNumbers.Length; layerNumber++)
                    {
                        currentVerticesNumbers[layerNumber] = GetVertexNumber(row, column, layerNumber);
                    }
                    if (row > 0)
                    {
                        for (int layerNumber = 0; layerNumber < otherVerticesNumbers.Length; layerNumber++)
                        {
                            otherVerticesNumbers[layerNumber] = GetVertexNumber(row - 1, column, layerNumber);
                        }
                        if (goodChars.Contains(maze[row - 1, column]))
                        {
                            for (int layerNumber = 0; layerNumber < currentVerticesNumbers.Length; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber]);
                            }
                        }

                        if (maze[row - 1, column] == 'X' && t != 0)
                        {
                            for (int layerNumber = 0; layerNumber < k; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber + 1], t);
                            }
                        }
                    }
                    if (row < totalRows - 1)
                    {
                        for (int layerNumber = 0; layerNumber < otherVerticesNumbers.Length; layerNumber++)
                        {
                            otherVerticesNumbers[layerNumber] = GetVertexNumber(row + 1, column, layerNumber);
                        }
                        if (goodChars.Contains(maze[row + 1, column]))
                        {
                            for (int layerNumber = 0; layerNumber < currentVerticesNumbers.Length; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber]);
                            }
                        }

                        if (maze[row + 1, column] == 'X' && t != 0)
                        {
                            for (int layerNumber = 0; layerNumber < k; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber + 1], t);
                            }
                        }
                    }
                    if (column > 0)
                    {
                        for (int layerNumber = 0; layerNumber < otherVerticesNumbers.Length; layerNumber++)
                        {
                            otherVerticesNumbers[layerNumber] = GetVertexNumber(row, column - 1, layerNumber);
                        }
                        if (goodChars.Contains(maze[row, column - 1]))
                        {
                            for (int layerNumber = 0; layerNumber < currentVerticesNumbers.Length; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber]);
                            }
                        }

                        if (maze[row, column - 1] == 'X' && t != 0)
                        {
                            for (int layerNumber = 0; layerNumber < k; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber + 1], t);
                            }
                        }
                    }
                    if (column < totalColumns - 1)
                    {
                        for (int layerNumber = 0; layerNumber < otherVerticesNumbers.Length; layerNumber++)
                        {
                            otherVerticesNumbers[layerNumber] = GetVertexNumber(row, column + 1, layerNumber);
                        }
                        if (goodChars.Contains(maze[row, column + 1]))
                        {
                            for (int layerNumber = 0; layerNumber < currentVerticesNumbers.Length; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber]);
                            }
                        }

                        if (maze[row, column + 1] == 'X' && t != 0)
                        {
                            for (int layerNumber = 0; layerNumber < k; layerNumber++)
                            {
                                g.AddEdge(currentVerticesNumbers[layerNumber], otherVerticesNumbers[layerNumber + 1], t);
                            }
                        }
                    }
                }
            }

            for (int layerNumber = 0; layerNumber < k; layerNumber++)
            {
                g.AddEdge(endVertices[layerNumber], endVertices[layerNumber + 1], 0);
                g.AddEdge(endVertices[layerNumber + 1], endVertices[layerNumber], 0);
            }
            bool result = g.DijkstraShortestPaths(startVerices[0], out PathsInfo[] pathsInfo);

            double length = pathsInfo[endVertices[k]].Dist;

            if (double.IsNaN(length))
            {
                path = "";
                return(-1);
            }
            else
            {
                Edge[] pathEdges = PathsInfo.ConstructPath(startVerices[0], endVertices[k], pathsInfo);

                StringBuilder pathStringBuilder = new StringBuilder();
                foreach (var edge in pathEdges)
                {
                    char direction = ConvertEdgeToChar(edge);
                    if (direction != '*')
                    {
                        pathStringBuilder.Append(direction);
                    }
                }

                path = pathStringBuilder.ToString();
                return((int)length);
            }

            //Edge[] pathEdges = PathsInfo.ConstructPath(startVertex, endVertex, pathsInfo);

            //StringBuilder pathStringBuilder = new StringBuilder();
            //foreach (var edge in pathEdges)
            //{
            //    pathStringBuilder.Append(ConvertEdgeToChar(edge));
            //}

            //path = pathStringBuilder.ToString();
            //if (true)
            //{

            //}
            //return double.IsNaN(length) ? -1 : (int)length;

            int GetVertexNumber(int row, int column, int layerNumber)
            {
                return(row * totalColumns + column + layerNumber * totalFields);
            }

            char ConvertEdgeToChar(Edge edge)
            {
                var startField = GetRowAndColumn(edge.From);
                var endField   = GetRowAndColumn(edge.To);

                if (startField.row == endField.row)
                {
                    if (endField.column > startField.column)
                    {
                        return('E');
                    }
                    else if (endField.column < startField.column)
                    {
                        return('W');
                    }
                    else if (endField.column == startField.column)
                    {
                        return('*');
                    }
                }
                else if (startField.column == endField.column)
                {
                    if (endField.row > startField.row)
                    {
                        return('S');
                    }
                    else if (endField.row < startField.row)
                    {
                        return('N');
                    }
                }
                throw new ArgumentException("Incorrect edge");
            }

            Field GetRowAndColumn(int vertexNumber)
            {
                int layerNumber = vertexNumber / totalFields;
                int row         = (vertexNumber - layerNumber * totalFields) / totalColumns;
                int column      = (vertexNumber - layerNumber * totalFields) - row * totalColumns;

                return(new Field(row, column));
            }
        }
Exemple #12
0
        /// <summary>
        /// Sprawdza możliwość przejazdu między dzielnicami-wielokątami district1 i district2,
        /// tzn. istnieją para ulic, pomiędzy którymi jest przejazd
        /// oraz fragment jednej ulicy należy do obszaru jednej z dzielnic i fragment drugiej należy do obszaru drugiej dzielnicy
        /// </summary>
        /// <returns>Informacja czy istnieje przejazd między dzielnicami</returns>
        // etap 4
        public bool CheckDistricts(Street[] streets, Point[] district1, Point[] district2, out List <int> path, out List <Point> intersections)
        {
            path          = new List <int>();
            intersections = new List <Point>();
            int   S  = streets.Length;
            int   n1 = district1.Length;
            int   n2 = district2.Length;
            Graph g  = new AdjacencyListsGraph <SimpleAdjacencyList>(false, S + 2); // 0..S-1 streets   S == district1, S + 1 == district2

            for (int i = 0; i < S; ++i)
            {
                // ulica wchodzi do district1
                for (int k = 0; k < n1; ++k)
                {
                    if (CheckIntersection(streets[i], new Street(district1[k % n1], district1[(k + 1) % n1])) != 0)
                    {
                        g.AddEdge(i, S);
                    }
                }

                // ulica wchodzi do district2
                for (int k = 0; k < n2; ++k)
                {
                    if (CheckIntersection(streets[i], new Street(district2[k % n2], district2[(k + 1) % n2])) != 0)
                    {
                        g.AddEdge(i, S + 1);
                    }
                }

                // ulica krzyzuje sie z kolejna ulica
                if (i != S - 1)
                {
                    for (int j = i + 1; j < S; ++j)
                    {
                        if (CheckIntersection(streets[i], streets[j]) != 0)
                        {
                            g.AddEdge(i, j);
                        }
                    }
                }
            }
            PathsInfo[] p = new PathsInfo[S + 2];
            ShortestPathsGraphExtender.DijkstraShortestPaths(g, S, out p);
            Edge[] e = PathsInfo.ConstructPath(S, S + 1, p);

            // jesli istnieje sciezka od S do S+1
            if (!Double.IsNaN(p[S + 1].Dist))
            {
                path = new List <int>();
                // pododawac kolejne pkty (bez S i bez S+1)
                for (int j = 0; j < e.Length - 1; ++j)
                {
                    path.Add(e[j].To);
                }

                intersections = new List <Point>();
                // przeciecia kolejnych ulic
                for (int j = 0; j < path.Count - 1; ++j)
                {
                    intersections.Add(GetIntersectionPoint(streets[path[j]], streets[path[j + 1]]));
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #13
0
        public (int c1, int c2, int?bypass, double time, Edge[] path)? FindBestCitiesPair(Graph times, double[] passThroughCityTimes, int[] nominatedCities, bool buildBypass)
        {
            int n = times.VerticesCount;


            int   c1 = -1, c2 = -1;
            Graph g = times.IsolatedVerticesGraph(true, n);


            for (int i = 0; i < n; i++)
            {
                foreach (var e in times.OutEdges(i))
                {
                    g.AddEdge(e.From, e.To, e.Weight + passThroughCityTimes[e.From]);
                }
            }

            PathsInfo[] opt = null;

            PathsInfo[][] sciezki = new PathsInfo[nominatedCities.Length][];

            double dystans = double.MaxValue;

            for (int i = 0; i < nominatedCities.Length; i++)
            {
                foreach (var e in g.OutEdges(nominatedCities[i]))
                {
                    g.ModifyEdgeWeight(e.From, e.To, -passThroughCityTimes[nominatedCities[i]]);
                }
                PathsInfo[] pi;

                g.DijkstraShortestPaths(nominatedCities[i], out pi);
                sciezki[i] = pi;

                for (int k = 0; k < nominatedCities.Length; k++)
                {
                    if (k == i)
                    {
                        continue;
                    }
                    if (GraphHelperExtender.IsNaN(pi[nominatedCities[k]].Dist) == true)
                    {
                        continue;
                    }
                    if (pi[nominatedCities[k]].Dist < dystans)
                    {
                        dystans = pi[nominatedCities[k]].Dist;
                        c1      = nominatedCities[i];
                        c2      = nominatedCities[k];
                        opt     = pi;
                    }
                }

                foreach (var e in g.OutEdges(nominatedCities[i]))
                {
                    g.ModifyEdgeWeight(e.From, e.To, passThroughCityTimes[nominatedCities[i]]);
                }
            }
            if (dystans == double.MaxValue)
            {
                return(null);
            }
            Edge[] sciezka = PathsInfo.ConstructPath(c1, c2, opt);
            if (buildBypass == false)
            {
                return(c1, c2, null, dystans, sciezka);
            }


            //ETAP 2
            int       obwodnica = -1;
            PathsInfo p1        = new PathsInfo();
            PathsInfo p2        = new PathsInfo();



            for (int i = 0; i < nominatedCities.Length; i++)
            {
                for (int j = 0; j < nominatedCities.Length; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }
                    for (int k = 0; k < n; k++)
                    {
                        if (k == nominatedCities[i] || k == nominatedCities[j])
                        {
                            continue;
                        }
                        if (sciezki[i][k].Dist + sciezki[j][k].Dist < dystans)
                        {
                            dystans   = sciezki[i][k].Dist + sciezki[j][k].Dist;
                            obwodnica = k;
                            //sciezki[i][k].Dist -= passThroughCityTimes[k];
                            c1 = nominatedCities[i];
                            c2 = nominatedCities[j];
                            p1 = sciezki[i][k];
                            p2 = sciezki[j][k];


                            //p1 = sciezki[i];
                            //sciezki[i][k].Dist += passThroughCityTimes[k];
                        }
                    }
                }
            }


            if (obwodnica == -1)
            {
                return(c1, c2, null, dystans, sciezka);
            }

            //sciezka = PathsInfo.ConstructPath(c1, c2,p1);

            int indc1 = -1;
            int indc2 = -1;

            for (int i = 0; i < n; i++)
            {
                if (nominatedCities[i] == c1)
                {
                    indc1 = i;
                    break;
                }
            }
            for (int j = 0; j < n; j++)
            {
                if (nominatedCities[j] == c2)
                {
                    indc2 = j;
                    break;
                }
            }



            List <Edge> sciezkapom = new List <Edge>();

            sciezkapom.Add((Edge)p1.Last);
            int ostatniwierzch = ((Edge)p1.Last).From;

            while (ostatniwierzch != c1)
            {
                sciezkapom.Add((Edge)sciezki[indc1][ostatniwierzch].Last);
                ostatniwierzch = ((Edge)sciezki[indc1][ostatniwierzch].Last).From;
            }
            sciezkapom.Reverse();
            sciezkapom.Add(new Edge(((Edge)p2.Last).To, ((Edge)p2.Last).From, ((Edge)p2.Last).Weight));
            ostatniwierzch = ((Edge)p2.Last).From;
            while (ostatniwierzch != c2)
            {
                sciezkapom.Add(new Edge(((Edge)sciezki[indc2][ostatniwierzch].Last).To, ((Edge)sciezki[indc2][ostatniwierzch].Last).From, ((Edge)sciezki[indc2][ostatniwierzch].Last).Weight));
                ostatniwierzch = ((Edge)sciezki[indc2][ostatniwierzch].Last).From;
            }
            sciezka = sciezkapom.ToArray();
            return(c1, c2, obwodnica, dystans, sciezka);
        }
Exemple #14
0
        /// <summary>
        /// Wersje zadania I oraz II
        /// Zwraca najkrótszy możliwy czas przejścia przez labirynt bez dynamitów lub z dowolną ich liczbą
        /// </summary>
        /// <param name="maze">labirynt</param>
        /// <param name="withDynamite">informacja, czy dostępne są dynamity
        /// Wersja I zadania -> withDynamites = false, Wersja II zadania -> withDynamites = true</param>
        /// <param name="path">zwracana ścieżka</param>
        /// <param name="t">czas zburzenia ściany (dotyczy tylko wersji II)</param>
        public int FindShortestPath(char[,] maze, bool withDynamite, out string path, int t = 0)
        {
            int x     = maze.GetLength(1);
            int y     = maze.GetLength(0);
            int vNo   = 0;
            int start = 0;
            int end   = 0;

            Graph g = new AdjacencyListsGraph <AVLAdjacencyList>(true, x * y);

            for (int i = 0; i < y; i++)
            {
                for (int j = 0; j < x; j++)
                {
                    //Get the neighbours, if it tries to go out of bounds set the neighbor to 'N'
                    char curChar = maze[i, j];
                    char left    = j >= 1 ? maze[i, j - 1] : 'N';
                    char right   = j < x - 1 ? maze[i, j + 1] : 'N';
                    char up      = i >= 1 ? maze[i - 1, j] : 'N';
                    char down    = i < y - 1 ? maze[i + 1, j] : 'N';

                    //If it comes across S or E, mark their vNo's (vertices number)
                    if (curChar == 'S')
                    {
                        start = vNo;
                    }
                    if (curChar == 'E')
                    {
                        end = vNo;
                    }

                    //Go through each neighbour and add proper edges if applicable
                    switch (up)
                    {
                    case 'N':
                        break;

                    case 'X':
                        if (withDynamite)
                        {
                            g.AddEdge(vNo, vNo - x, t);
                        }
                        break;

                    default:
                        g.AddEdge(vNo, vNo - x);
                        break;
                    }
                    switch (down)
                    {
                    case 'N':
                        break;

                    case 'X':
                        if (withDynamite)
                        {
                            g.AddEdge(vNo, vNo + x, t);
                        }
                        break;

                    default:
                        g.AddEdge(vNo, vNo + x);
                        break;
                    }
                    switch (left)
                    {
                    case 'N':
                        break;

                    case 'X':
                        if (withDynamite)
                        {
                            g.AddEdge(vNo, vNo - 1, t);
                        }
                        break;

                    default:
                        g.AddEdge(vNo, vNo - 1);
                        break;
                    }
                    switch (right)
                    {
                    case 'N':
                        break;

                    case 'X':
                        if (withDynamite)
                        {
                            g.AddEdge(vNo, vNo + 1, t);
                        }
                        break;

                    default:
                        g.AddEdge(vNo, vNo + 1);
                        break;
                    }
                    vNo++;
                }
            }

            path = "";
            PathsInfo[] paths;
            if (!g.DijkstraShortestPaths(start, out paths))
            {
                return(-1);
            }

            if (paths[end].Last == null)
            {
                return(-1);
            }

            Edge[]        edgePath = PathsInfo.ConstructPath(start, end, paths);
            StringBuilder str      = new StringBuilder();

            for (int i = 0; i < edgePath.Length; i++)
            {
                int curXFrom = edgePath[i].From / x;
                int curYFrom = edgePath[i].From - x * curXFrom;
                int curXTo   = edgePath[i].To / x;
                int curYTo   = edgePath[i].To - x * curXTo;

                if (curXFrom == curXTo)
                {
                    if (curYFrom < curYTo)
                    {
                        str.Append('E');
                    }
                    else
                    {
                        str.Append('W');
                    }
                }
                else
                {
                    if (curXFrom < curXTo)
                    {
                        str.Append('S');
                    }
                    else
                    {
                        str.Append('N');
                    }
                }
            }
            path = str.ToString();
            return((int)paths[end].Dist);
        }
        /// <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).
        /// Dopuszczamy, aby na ścieżce powtarzały się wierzchołki/krawędzie.
        /// Można założyć, że a!=b oraz że w grafie nie występują pętle.
        /// </summary>
        /// <remarks>
        /// Wymagana złożoność do O(D), gdzie D jest złożonością implementacji alogorytmu 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ść znalezionej ścieżki</returns>
        public static double?FindSecondShortestPath(this Graph g, int a, int b, out Edge[] path)
        {
            PathsInfo[] pi;
            PathsInfo[] pi2;
            Graph       G = g.Clone();

            G.DijkstraShortestPaths(a, out pi);

            if (double.IsNaN(pi[b].Dist))
            {
                path = null;
                return(null);
            }

            Edge[] firstPath = PathsInfo.ConstructPath(a, b, pi);

            List <Edge> finalPath = new List <Edge>();

            if (G.Directed)
            {
                G = G.Reverse();
            }

            G.DijkstraShortestPaths(b, out pi2);

            if (pi2 == null)
            {
                path = null;
                return(null);
            }

            int u = -1, v = -1;

            double secondShortest = double.PositiveInfinity;

            for (int i = firstPath.Length - 1; i >= 0; i--)
            {
                foreach (Edge ed in g.OutEdges(firstPath[i].From))
                {
                    if (ed.To != firstPath[i].To)
                    {
                        double current;

                        if (double.IsNaN(pi2[ed.To].Dist))
                        {
                            continue;
                        }

                        if ((current = (ed.Weight + pi[firstPath[i].From].Dist + pi2[ed.To].Dist)) < secondShortest)
                        {
                            secondShortest = current;
                            u = firstPath[i].From;
                            v = ed.To;
                        }
                    }
                }
            }

            if (u == -1)
            {
                path = null;
                return(null);
            }

            int ind = 0;

            while (firstPath[ind].From != u)
            {
                finalPath.Add(firstPath[ind++]);
            }

            Edge[] second = PathsInfo.ConstructPath(b, v, pi2);

            finalPath.Add(new Edge(u, v, g.GetEdgeWeight(u, v)));
            ind = v;
            Edge?last;

            while ((last = pi2[ind].Last) != null)
            {
                Edge e = pi2[ind].Last.Value;
                finalPath.Add(new Edge(e.To, e.From, e.Weight));
                ind = last.Value.From;
            }
            path = finalPath.ToArray();
            return(secondShortest);
        }
Exemple #16
0
        public (int c1, int c2, int?bypass, double time, Edge[] path)? FindBestCitiesPair(Graph times, double[] passThroughCityTimes, int[] nominatedCities, bool buildBypass)
        {
            Graph  g     = times.IsolatedVerticesGraph(true, times.VerticesCount);
            int    c1    = -1;
            int    c2    = -1;
            int    city1 = -1;
            int    city2 = -1;
            double best  = double.MaxValue;

            for (int i = 0; i < times.VerticesCount; i++)
            {
                foreach (Edge e in times.OutEdges(i))
                {
                    g.AddEdge(e.To, e.From, e.Weight + passThroughCityTimes[e.To]);
                    g.AddEdge(e.From, e.To, e.Weight + passThroughCityTimes[e.From]);
                }
            }
            PathsInfo[][] distance = new PathsInfo[nominatedCities.Length][];
            for (int i = 0; i < nominatedCities.Length; i++)
            {
                foreach (Edge e in g.OutEdges(nominatedCities[i]))
                {
                    g.ModifyEdgeWeight(e.From, e.To, -passThroughCityTimes[nominatedCities[i]]);
                }
                g.DijkstraShortestPaths(nominatedCities[i], out distance[i]);
                foreach (Edge e in g.OutEdges(nominatedCities[i]))
                {
                    g.ModifyEdgeWeight(e.From, e.To, passThroughCityTimes[nominatedCities[i]]);
                }
                for (int j = 0; j < nominatedCities.Length; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }
                    if (distance[i][nominatedCities[j]].Dist.IsNaN())
                    {
                        continue;
                    }
                    if ((distance[i][nominatedCities[j]].Dist < best))
                    {
                        best  = distance[i][nominatedCities[j]].Dist;
                        c1    = nominatedCities[i];
                        c2    = nominatedCities[j];
                        city1 = i;
                        city2 = j;
                    }
                }
            }
            if (best == double.MaxValue)
            {
                return(null);
            }
            Edge[] path = PathsInfo.ConstructPath(c1, c2, distance[city1]);
            if (buildBypass == false)
            {
                return(c1, c2, null, best, path);
            }
            PathsInfo firstPart    = new PathsInfo();
            PathsInfo secondPart   = new PathsInfo();
            int       passedVertex = -1;

            for (int i = 0; i < nominatedCities.Length; i++)
            {
                for (int j = 0; j < nominatedCities.Length; j++)
                {
                    if (i == j)
                    {
                        continue;
                    }
                    for (int z = 0; z < times.VerticesCount; z++)
                    {
                        if (z == nominatedCities[i] || z == nominatedCities[j])
                        {
                            continue;
                        }
                        if (distance[i][z].Dist.IsNaN() || distance[j][z].Dist.IsNaN())
                        {
                            continue;
                        }
                        if (distance[i][z].Dist + distance[j][z].Dist < best)
                        {
                            passedVertex = z;
                            firstPart    = distance[i][z];
                            secondPart   = distance[j][z];
                            best         = distance[i][z].Dist + distance[j][z].Dist;
                            c1           = nominatedCities[i];
                            c2           = nominatedCities[j];
                            city1        = i;
                            city2        = j;
                        }
                    }
                }
            }
            if (passedVertex == -1)
            {
                return(c1, c2, null, best, path);
            }
            List <Edge> tmp  = new List <Edge>();
            List <Edge> tmp2 = new List <Edge>();

            tmp.Add((Edge)firstPart.Last);
            int prev = ((Edge)firstPart.Last).From;

            while (prev != c1)
            {
                tmp.Add((Edge)distance[city1][prev].Last);
                prev = ((Edge)distance[city1][prev].Last).From;
            }
            tmp2.Add(new Edge(((Edge)secondPart.Last).To, ((Edge)secondPart.Last).From, ((Edge)secondPart.Last).Weight));
            prev = ((Edge)secondPart.Last).From;
            while (prev != c2)
            {
                tmp2.Add(new Edge(((Edge)distance[city2][prev].Last).To, ((Edge)distance[city2][prev].Last).From, ((Edge)distance[city2][prev].Last).Weight));
                prev = ((Edge)distance[city2][prev].Last).From;
            }
            tmp.Reverse();
            foreach (Edge e in tmp2)
            {
                tmp.Add(e);
            }
            return(c1, c2, passedVertex, best, tmp.ToArray());
        }
Exemple #17
0
        public (int c1, int c2, int?bypass, double time, Edge[] path)? FindBestCitiesPair(Graph times, double[] passThroughCityTimes, int[] nominatedCities, bool buildBypass)
        {
            var g_cloned = times.Clone();

            int n = g_cloned.VerticesCount;

            for (int v = 0; v < n; v++)
            {
                foreach (Edge e in g_cloned.OutEdges(v))
                {
                    g_cloned.ModifyEdgeWeight(v, e.To, passThroughCityTimes[v] / 2);
                }
            }

            if (!buildBypass)
            {
                int         minCity1       = int.MaxValue;
                int         minCity2       = int.MaxValue;
                double      time           = double.MaxValue;
                PathsInfo[] tmpTmpPathInfo = { };
                PathsInfo[] tmpPathInfo    = { };
                Edge[]      shortestPath   = { };

                for (int i = 0; i < nominatedCities.Length; i++)
                //foreach (var start in nominatedCities)
                {
                    int start = nominatedCities[i];

                    double minDistTmp      = double.MaxValue;
                    int    minCityTmp      = -1;
                    Edge[] shortestPathTmp = { };

                    g_cloned.DijkstraShortestPaths(start, out PathsInfo[] d);

                    for (int j = i; j < nominatedCities.Length; j++)
                    //foreach (var end in nominatedCities)
                    {
                        int end = nominatedCities[j];
                        if (start != end)
                        {
                            d[end].Dist -= passThroughCityTimes[end] / 2 + passThroughCityTimes[start] / 2;

                            if (d[end].Dist < time && d[end].Dist < minDistTmp)
                            {
                                minDistTmp     = d[end].Dist;
                                minCityTmp     = end;
                                tmpTmpPathInfo = d;
                            }
                        }
                    }
                    if (minCityTmp != -1)
                    {
                        if (time > minDistTmp)
                        {
                            time        = minDistTmp;
                            minCity1    = start;
                            minCity2    = minCityTmp;
                            tmpPathInfo = tmpTmpPathInfo;
                        }
                    }
                }

                if (time == double.MaxValue)
                {
                    return(null);
                }
                else
                {
                    shortestPath = PathsInfo.ConstructPath(minCity1, minCity2, tmpPathInfo);
                }

                return(minCity1, minCity2, null, time, shortestPath);
            }
            else /*budujemy obwodnicę*/
            {
                int         minCity1     = int.MaxValue;
                int         minCity2     = int.MaxValue;
                double      time         = double.MaxValue;
                Edge[]      shortestPath = { };
                int         byPassCity   = -1;
                PathsInfo[] tmpPathInfo  = { };
                int         i1           = -1;
                int         j1           = -1;

                //var pathsToAllVertices = new HashTable<int, PathsInfo[]>();

                var pathsToAllVerticesTab = new PathsInfo[nominatedCities.Length][];

                for (int i = 0; i < nominatedCities.Length; i++)

                {
                    int start = nominatedCities[i];

                    g_cloned.DijkstraShortestPaths(start, out PathsInfo[] d);
                    //pathsToAllVertices.Insert(start, d);
                    pathsToAllVerticesTab[i] = d;
                    for (int j = i; j < nominatedCities.Length; j++)

                    {
                        int end = nominatedCities[j];
                        if (start != end)
                        {
                            d[end].Dist -= passThroughCityTimes[end] / 2 + passThroughCityTimes[start] / 2;

                            if (d[end].Dist < time)
                            {
                                time        = d[end].Dist;
                                minCity1    = start;
                                minCity2    = end;
                                tmpPathInfo = d;
                                i1          = i;
                                j1          = j;
                            }
                        }
                    }
                }

                for (int i = 0; i < nominatedCities.Length; i++)
                {
                    int start = nominatedCities[i];

                    for (int j = i; j < nominatedCities.Length; j++)

                    {
                        int end = nominatedCities[j];
                        for (int ii = 0; ii < g_cloned.VerticesCount; ii++)
                        {
                            if (start != end && ii != start && ii != end)
                            {
                                double timeThroughICity = pathsToAllVerticesTab[i][ii].Dist + pathsToAllVerticesTab[j][ii].Dist - passThroughCityTimes[ii] -
                                                          0.5 * passThroughCityTimes[start] - 0.5 * passThroughCityTimes[end];

                                if (timeThroughICity < time && timeThroughICity >= 0)
                                {
                                    byPassCity = ii;
                                    time       = timeThroughICity;
                                    minCity1   = start;
                                    minCity2   = end;
                                    i1         = i;
                                    j1         = j;
                                }
                            }
                        }
                    }
                }


                if (time == double.MaxValue)
                {
                    return(null);
                }
                else if (byPassCity != -1)
                {
                    var path1 = PathsInfo.ConstructPath(minCity1, byPassCity, pathsToAllVerticesTab[i1]);
                    var path2 = PathsInfo.ConstructPath(minCity2, byPassCity, pathsToAllVerticesTab[j1]);
                    Array.Reverse(path2);

                    for (int i = 0; i < path2.Length; i++)
                    {
                        path2[i] = new Edge(path2[i].To, path2[i].From);
                    }

                    shortestPath = new Edge[path1.Length + path2.Length];
                    Array.Copy(path1, shortestPath, path1.Length);
                    Array.Copy(path2, 0, shortestPath, path1.Length, path2.Length);
                }
                else
                {
                    shortestPath = PathsInfo.ConstructPath(minCity1, minCity2, tmpPathInfo);
                }


                if (byPassCity == -1)
                {
                    return(minCity1, minCity2, null, time, shortestPath);
                }
                return(minCity1, minCity2, byPassCity, time, shortestPath);
            }
        }
        /// <summary>
        /// Sprawdza możliwość przejazdu między dzielnicami-wielokątami district1 i district2,
        /// tzn. istnieją para ulic, pomiędzy którymi jest przejazd
        /// oraz fragment jednej ulicy należy do obszaru jednej z dzielnic i fragment drugiej należy do obszaru drugiej dzielnicy
        /// </summary>
        /// <returns>Informacja czy istnieje przejazd między dzielnicami</returns>
        public bool CheckDistricts(Street[] streets, Point[] district1, Point[] district2, out List <int> path, out List <Point> intersections)
        {
            int   n = streets.Length;
            Graph g = new AdjacencyListsGraph <HashTableAdjacencyList>(false, n + 2);

            int source = n;
            int target = n + 1;

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < district1.Length; j++)
                {
                    int result = CheckIntersection(streets[i], new Street(district1[j], district1[(j + 1) % district1.Length]));
                    if (result == 1 || result == int.MaxValue)
                    {
                        g.AddEdge(source, i);
                    }
                }
                for (int j = 0; j < district2.Length; j++)
                {
                    int result = CheckIntersection(streets[i], new Street(district2[j], district2[(j + 1) % district2.Length]));
                    if (result == 1 || result == int.MaxValue)
                    {
                        g.AddEdge(i, target);
                    }
                }
                for (int j = i + 1; j < n; j++)
                {
                    int result = CheckIntersection(streets[i], streets[j]);
                    if (result == 1)
                    {
                        g.AddEdge(i, j);
                    }
                    else if (result == int.MaxValue)
                    {
                        throw new ArgumentException();
                    }
                }
            }

            g.DijkstraShortestPaths(source, out PathsInfo[] d);

            path          = new List <int>();
            intersections = new List <Point>();

            if (d[target].Dist.IsNaN())
            {
                return(false);
            }

            Edge[] edges    = PathsInfo.ConstructPath(source, target, d);
            int    previous = -1;

            for (int i = 0; i < edges.Length - 1; i++)
            {
                path.Add(edges[i].To);
                if (previous != -1)
                {
                    intersections.Add(GetIntersectionPoint(streets[previous], streets[edges[i].To]));
                }
                previous = edges[i].To;
            }

            return(true);
        }
Exemple #19
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).
        /// Dopuszczamy, aby na ścieżce powtarzały się wierzchołki/krawędzie.
        /// Można założyć, że a!=b oraz że w grafie nie występują pętle.
        /// </summary>
        /// <remarks>
        /// Wymagana złożoność do O(D), gdzie D jest złożonością implementacji alogorytmu 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ść znalezionej ścieżki</returns>
        public static double?FindSecondShortestPath(this Graph g, int a, int b, out Edge[] path)
        {
            path = null;
            double?min = Double.MaxValue;

            PathsInfo[] d;
            Graph       G;
            Edge        edge  = new Edge();
            int         index = 0;

            if (g.Directed)
            {
                G = g.Reverse();
            }
            else
            {
                G = g;
            }

            G.DijkstraShortestPaths(b, out d);
            if (d[a].Dist.IsNaN())
            {
                return(null);
            }

            Edge[] firstpath = PathsInfo.ConstructPath(b, a, d);

            for (int i = 0; i < firstpath.Length; i++)
            {
                int v = firstpath[i].To;
                foreach (Edge e in g.OutEdges(v))
                {
                    if (e.To != firstpath[i].From && d[e.To].Dist + e.Weight + d[a].Dist - d[v].Dist < min)
                    {
                        min   = d[e.To].Dist + e.Weight + d[a].Dist - d[v].Dist;
                        edge  = e;
                        index = i;
                    }
                }
            }

            if (min == Double.MaxValue)
            {
                return(null);
            }

            Edge[] tmp = PathsInfo.ConstructPath(b, edge.To, d);
            Array.Reverse(tmp);
            for (int i = 0; i < tmp.Length; i++)
            {
                tmp[i] = new Edge(tmp[i].To, tmp[i].From, tmp[i].Weight);
            }

            path = new Edge[firstpath.Length - index + tmp.Length];
            for (int i = 0; i < firstpath.Length - index - 1; i++)
            {
                path[i] = new Edge(firstpath[firstpath.Length - i - 1].To, firstpath[firstpath.Length - i - 1].From, firstpath[firstpath.Length - i - 1].Weight);
            }
            path[firstpath.Length - index - 1] = edge;
            Array.Copy(tmp, 0, path, firstpath.Length - index, tmp.Length);

            return(min);
        }
        /// <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).
        /// Dopuszczamy, aby na ścieżce powtarzały się wierzchołki/krawędzie.
        /// Można założyć, że a!=b oraz że w grafie nie występują pętle.
        /// </summary>
        /// <remarks>
        /// Wymagana złożoność do O(D), gdzie D jest złożonością implementacji alogorytmu 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ść znalezionej ścieżki</returns>
        public static double?FindSecondShortestPath(this Graph g, int a, int b, out Edge[] path)
        {
            PathsInfo[] d, dC;
            g.DijkstraShortestPaths(a, out d);
            Graph gC;

            if (g.Directed)
            {
                gC = g.Clone().Reverse();
            }
            else
            {
                gC = g;
            }
            gC.DijkstraShortestPaths(b, out dC);
            Edge[] shortestPath = PathsInfo.ConstructPath(a, b, d);
            if (null == shortestPath)
            {
                path = null;
                return(null);
            }
            double minDist = double.MaxValue;
            int    c = -1, c2 = -1;
            Edge   tE        = new Edge();
            bool   foundSame = false;

            foreach (Edge e in shortestPath)
            {
                if (foundSame)
                {
                    break;
                }
                foreach (Edge e2 in g.OutEdges(e.From))
                {
                    if (e2.To == e.To)
                    {
                        continue;
                    }
                    double currMin = dC[e2.To].Dist + d[e.From].Dist + e2.Weight;
                    if (minDist > currMin)
                    {
                        tE      = e2;
                        c       = e.From;
                        c2      = e2.To;
                        minDist = currMin;
                    }
                    if (currMin == d[b].Dist)
                    {
                        break;
                    }
                }
            }

            if (c2 == -1)
            {
                path = null;
                return(null);
            }
            gC.DijkstraShortestPaths(c2, out dC);
            Edge[]      shortestPath1 = PathsInfo.ConstructPath(a, c, d);
            Edge[]      shortestPath3 = PathsInfo.ConstructPath(c2, b, dC);
            List <Edge> z             = new List <Edge>();

            if (g.Directed)
            {
                gC.DijkstraShortestPaths(b, out dC);
                shortestPath3 = PathsInfo.ConstructPath(b, c2, dC);
            }
            foreach (Edge e in shortestPath1)
            {
                z.Add(e);
            }
            z.Add(tE);
            if (shortestPath3 == null)
            {
                path = null;
                return(null);
            }
            List <Edge> z2 = new List <Edge>();

            foreach (Edge e in shortestPath3)
            {
                if (!g.Directed)
                {
                    z.Add(e);
                }
                z2.Add(e);
            }
            if (g.Directed)
            {
                z2.Reverse();
                foreach (Edge e in z2)
                {
                    z.Add(new Edge(e.To, e.From, e.Weight));
                }
            }
            path = z.ToArray(); // shortestPath1 + tE + shortestPath3
            return(minDist);
        }
Exemple #21
0
        /// <summary>
        /// Wersja III i IV zadania
        /// Zwraca najkrótszy możliwy czas przejścia przez labirynt z użyciem co najwyżej k lasek dynamitu
        /// </summary>
        /// <param name="maze">labirynt</param>
        /// <param name="k">liczba dostępnych lasek dynamitu, dla wersji III k=1</param>
        /// <param name="path">zwracana ścieżka</param>
        /// <param name="t">czas zburzenia ściany</param>
        public int FindShortestPathWithKDynamites(char[,] maze, int k, out string path, int t)
        {
            int x           = maze.GetLength(1);
            int y           = maze.GetLength(0);
            int layerOffset = x * y;
            int vNo         = 0;
            int start       = 0;
            int end         = 0;

            Graph g = new AdjacencyListsGraph <AVLAdjacencyList>(true, (k + 1) * x * y);

            for (int p = 0; p <= k; p++)
            {
                for (int i = 0; i < y; i++)
                {
                    for (int j = 0; j < x; j++)
                    {
                        if (maze[i, j] == 'S' && p == 0)
                        {
                            start = vNo;
                        }
                        if (maze[i, j] == 'E')
                        {
                            end = vNo;
                        }

                        char up    = i >= 1 ? maze[i - 1, j] : 'N';
                        char down  = i < y - 1 ? maze[i + 1, j] : 'N';
                        char left  = j >= 1 ? maze[i, j - 1] : 'N';
                        char right = j < x - 1 ? maze[i, j + 1] : 'N';

                        int nextLayerVert = vNo + layerOffset;
                        switch (up)
                        {
                        case 'X':
                            if (p < k)
                            {
                                g.AddEdge(vNo, nextLayerVert - x, t);
                            }
                            break;

                        case 'N':
                            break;

                        default:
                            g.AddEdge(vNo, vNo - x);
                            break;
                        }
                        switch (down)
                        {
                        case 'X':
                            if (p < k)
                            {
                                g.AddEdge(vNo, nextLayerVert + x, t);
                            }
                            break;

                        case 'N':
                            break;

                        default:
                            g.AddEdge(vNo, vNo + x);
                            break;
                        }
                        switch (left)
                        {
                        case 'X':
                            if (p < k)
                            {
                                g.AddEdge(vNo, nextLayerVert - 1, t);
                            }
                            break;

                        case 'N':
                            break;

                        default:
                            g.AddEdge(vNo, vNo - 1);
                            break;
                        }
                        switch (right)
                        {
                        case 'X':
                            if (p < k)
                            {
                                g.AddEdge(vNo, nextLayerVert + 1, t);
                            }
                            break;

                        case 'N':
                            break;

                        default:
                            g.AddEdge(vNo, vNo + 1);
                            break;
                        }
                        vNo++;
                    }
                }
            }

            path = "";
            PathsInfo[] paths;
            if (!g.DijkstraShortestPaths(start, out paths))
            {
                return(-1);
            }

            int res         = -1;
            int minEnd      = -1;
            int minEndValue = int.MaxValue;

            while (end >= 0)
            {
                if (paths[end].Last != null)
                {
                    res = (int)paths[end].Dist;
                    if (res < minEndValue)
                    {
                        minEnd      = end;
                        minEndValue = res;
                    }
                }
                end -= layerOffset;
            }
            if (minEnd < 0)
            {
                return(-1);
            }

            //GET THE PATH
            Edge[]        edgePath = PathsInfo.ConstructPath(start, minEnd, paths);
            StringBuilder str      = new StringBuilder();

            for (int i = 0; i < edgePath.Length; i++)
            {
                int layerFrom = edgePath[i].From / layerOffset;
                int layerTo   = edgePath[i].To / layerOffset;

                int normalvNoFrom = edgePath[i].From - layerFrom * layerOffset;
                int normalvNoTo   = edgePath[i].To - layerTo * layerOffset;

                int curXFrom = normalvNoFrom / x;
                int curYFrom = normalvNoFrom - x * curXFrom;
                int curXTo   = normalvNoTo / x;
                int curYTo   = normalvNoTo - x * curXTo;

                if (curXFrom == curXTo)
                {
                    if (curYFrom < curYTo)
                    {
                        str.Append('E');
                    }
                    else
                    {
                        str.Append('W');
                    }
                }
                else
                {
                    if (curXFrom < curXTo)
                    {
                        str.Append('S');
                    }
                    else
                    {
                        str.Append('N');
                    }
                }
            }
            path = str.ToString();
            return(minEndValue);
        }