示例#1
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);
        }
示例#2
0
文件: City.cs 项目: sikoraa/asd2
        /// <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);
            }
        }
        /// <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);
        }
示例#4
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);
        }
示例#5
0
        // return: tak jak w punkcie poprzednim, ale tym razem uznajemy zarówno koszt przechodzenia przez miasta, jak i wielkość miasta startowego z którego wyruszają pielgrzymi.
        // Szczegółowo opisane jest to w treści zadania "Częśc 2".
        // minCost: najlepszy 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[] FindBestLocationSecondMetric(out int minCost, out Graph paths)
        {
            const int noEdge = 10000;

            minCost = -1;
            paths   = RoadsGraph.IsolatedVerticesGraph(true, RoadsGraph.VerticesCount);
            int[] ret = new int[RoadsGraph.VerticesCount];

            PathsInfo[]   bestPaths = null;
            PathsInfo[]   curPaths;
            PathsInfo[][] allPaths = new PathsInfo[RoadsGraph.VerticesCount][];

            int[] costSum = new int[RoadsGraph.VerticesCount];
            int[] costCur = new int[RoadsGraph.VerticesCount];

            // Dla każdego wierzchołka tworzymy nowy graf, liczymy koszty dojścia
            // z tego wierzchołka do innych i sumujemy wyniki z resztą w costSum
            for (int v = 0; v < RoadsGraph.VerticesCount; v++)
            {
                // Utworzenie grafu ze zmodyfikowanymi wagami:
                var tmp = RoadsGraph.IsolatedVerticesGraph(true, RoadsGraph.VerticesCount);
                for (int i = 0; i < RoadsGraph.VerticesCount; i++)
                {
                    foreach (Edge e in RoadsGraph.OutEdges(i))
                    {
                        tmp.AddEdge(e.From, e.To, Math.Min(e.Weight, CityCosts[v]) + Math.Min(CityCosts[e.From], CityCosts[v]));
                    }
                }


                for (int j = 0; j < RoadsGraph.VerticesCount; j++)
                {
                    costCur[j] = 0;
                }

                // Obliczenie kosztów w nowym grafie:
                tmp.DijkstraShortestPaths(v, out curPaths);

                allPaths[v] = curPaths;

                for (int j = 0; j < RoadsGraph.VerticesCount; j++)
                {
                    if (j == v)
                    {
                        continue;
                    }
                    if (curPaths[j].Dist == null)
                    {
                        costCur[j] += noEdge;
                    }
                    else
                    {
                        costCur[j] += curPaths[j].Dist.Value;
                    }
                }


                // Dodanie do reszty kosztów:
                for (int i = 0; i < RoadsGraph.VerticesCount; i++)
                {
                    if (i == v)
                    {
                        continue;
                    }
                    costSum[i] += costCur[i];
                }
            }

            int bestCost = int.MaxValue;
            int bestCity = 0;

            // Wybór najlepszego miasta:
            for (int i = 0; i < RoadsGraph.VerticesCount; i++)
            {
                if (costSum[i] < bestCost)
                {
                    bestCost = costSum[i];
                    bestCity = i;
                }
            }
            bestPaths = allPaths[bestCity];

            // Konstrukcja grafu:
            for (int i = 0; i < RoadsGraph.VerticesCount; i++)
            {
                if (i == bestCity)
                {
                    continue;
                }

                if (bestPaths[i].Dist == null)
                {
                    paths.AddEdge(i, bestCity, noEdge);
                }
                else
                {
                    int j = i;
                    while (j != bestCity)
                    {
                        paths.AddEdge(bestPaths[j].Last.Value.To, bestPaths[j].Last.Value.From,
                                      RoadsGraph.GetEdgeWeight(bestPaths[j].Last.Value.To, bestPaths[j].Last.Value.From).Value);
                        j = bestPaths[j].Last.Value.From;
                    }
                }
            }

            minCost = bestCost;
            return(costSum);
        }
示例#6
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);
            }
        }
示例#7
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());
        }
示例#8
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)
        {
            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);
        }
示例#9
0
        public (int c1, int c2, int?bypass, double time, Edge[] path)? FindBestCitiesPair(Graph times, double[] passThroughCityTimes, int[] nominatedCities, bool buildBypass)
        {
            double min = double.MaxValue;

            PathsInfo[][] tab = new PathsInfo[times.VerticesCount][];
            int           a   = -1;
            int           b   = -1;

            PathsInfo[] best = new PathsInfo[times.VerticesCount];

            Graph g = new AdjacencyListsGraph <HashTableAdjacencyList>(true, times.VerticesCount);

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

            for (int i1 = 0; i1 < nominatedCities.Length; ++i1)
            {
                int i = nominatedCities[i1];
                foreach (var e in g.OutEdges(i))
                {
                    g.DelEdge(e);
                    g.AddEdge(e.From, e.To, e.Weight - passThroughCityTimes[i]);
                }
                g.DijkstraShortestPaths(i, out tab[i]);
                for (int j = 0; j < g.VerticesCount; ++j)
                {
                    if (j != i && tab[i][j].Dist <= min && nominatedCities.Contains(j))
                    {
                        min = tab[i][j].Dist;
                        a   = i;
                        b   = j;
                    }
                }
            }

            double minTmp = double.MaxValue;
            int    x1 = -1, y1 = -1, k1 = -1;

            if (buildBypass)
            {
                for (int i = 0; i < nominatedCities.Length; ++i)
                {
                    int x = nominatedCities[i];
                    if (times.OutDegree(x) == 0)
                    {
                        continue;
                    }
                    for (int j = i + 1; j < nominatedCities.Length; ++j)
                    {
                        int y = nominatedCities[j];
                        if (times.OutDegree(y) == 0)
                        {
                            continue;
                        }
                        for (int k = 0; k < times.VerticesCount; ++k)
                        {
                            if (tab[x][k].Dist + tab[y][k].Dist < minTmp)
                            {
                                minTmp = tab[x][k].Dist + tab[y][k].Dist;
                                x1     = x;
                                y1     = y;
                                k1     = k;
                            }
                        }
                    }
                }
            }

            if (a == -1 || b == -1 || min == double.MaxValue)
            {
                return(null);
            }

            if (minTmp < min)
            {
                List <Edge> lst = new List <Edge>();
                int         ind = k1;
                best = tab[x1];
                while (best[ind].Last.HasValue)
                {
                    Edge e = best[ind].Last.Value;
                    lst.Insert(0, e);
                    ind = e.From;
                }
                ind  = k1;
                best = tab[y1];
                while (best[ind].Last.HasValue)
                {
                    Edge e = best[ind].Last.Value;
                    lst.Add(new Edge(e.To, e.From, e.Weight));
                    ind = e.From;
                }
                Edge[] path = lst.ToArray();
                return(x1, y1, k1, minTmp, path);
            }
            else
            {
                List <Edge> lst = new List <Edge>();
                int         ind = b;
                best = tab[a];
                while (best[ind].Last.HasValue)
                {
                    Edge e = best[ind].Last.Value;
                    lst.Insert(0, e);
                    ind = e.From;
                }
                Edge[] path = lst.ToArray();
                return(a, b, null, min, path);
            }
        }
示例#10
0
文件: Maze.cs 项目: barankiewicz/asd2
        /// <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);
        }
示例#11
0
文件: Maze.cs 项目: barankiewicz/asd2
        /// <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);
        }