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); }
/// <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); }
/// <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); }
// 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); }
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); } }
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()); }
/// <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); }
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); } }
/// <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> /// 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); }