/// <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); }
/// <summary> /// Algorytm znajdujący drugą pod względem długości najkrótszą ścieżkę między a i b. /// Możliwe, że jej długość jest równa najkrótszej (jeśli są dwie najkrótsze ścieżki, /// algorytm zwróci jedną z nich). /// Wymagamy, aby na ścieżce nie było powtórzeń wierzchołków ani krawędzi. /// Można założyć, że a!=b oraz że w grafie nie występują pętle. /// </summary> /// <remarks> /// Wymagana złożoność to O(nD), gdzie D jest złożonością implementacji algorytmu Dijkstry w bibliotece Graph. /// </remarks> /// <param name="g"></param> /// <param name="path">null jeśli druga ścieżka nie istnieje, wpp ściezka jako ciąg krawędzi</param> /// <returns>null jeśli druga ścieżka nie istnieje, wpp długość tej ścieżki</returns> public static double?FindSecondSimpleShortestPath(this Graph g, int a, int b, out Edge[] path) { path = null; PathsInfo[] bestPathInfo, tempPathInfo, secondBestPathInfo = null; double secondBest = double.PositiveInfinity; EdgesStack stack = new EdgesStack(); if (!g.DijkstraShortestPaths(a, out bestPathInfo)) { return(null); } int v = b; int pathCount = 0; while (bestPathInfo[v].Last != null) { stack.Put((Edge)bestPathInfo[v].Last); v = stack.Peek().From; pathCount++; } Edge deleted; while (!stack.Empty) { deleted = stack.Get(); g.DelEdge(deleted); g.DijkstraShortestPaths(a, out tempPathInfo); if (tempPathInfo[b].Dist < secondBest) { secondBestPathInfo = tempPathInfo; secondBest = tempPathInfo[b].Dist; } g.AddEdge(deleted); } List <Edge> pathList = new List <Edge>(); v = b; if (!double.IsPositiveInfinity(secondBest)) { while (secondBestPathInfo[v].Last != null) { pathList.Add((Edge)secondBestPathInfo[v].Last); v = pathList.Last().From; } pathList.Reverse(); path = pathList.ToArray(); } if (path == null) { return(null); } else { return(pathList.Sum(edge => edge.Weight)); } }
/// <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); }
/// <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> /// 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); }
/// <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); }
/// <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; PathsInfo[] reversePathInfo; List <Edge> bestPath = new List <Edge>(); if (g.Directed) { Graph gReversed = g.Reverse(); if (!gReversed.DijkstraShortestPaths(b, out reversePathInfo)) { return(null); } } else if (!g.DijkstraShortestPaths(b, out reversePathInfo)) { return(null); } int v = a; while (reversePathInfo[v].Last != null) { var last = (Edge)reversePathInfo[v].Last; bestPath.Add(new Edge(last.To, last.From, last.Weight)); v = last.From; } double currentDistance = 0.0; double secondDistance = double.PositiveInfinity; Edge extended = new Edge(-1, -1, double.PositiveInfinity); foreach (var currentEdge in bestPath) { foreach (var e in g.OutEdges(currentEdge.From)) { if (e == currentEdge) { continue; } if (currentDistance + e.Weight + reversePathInfo[e.To].Dist <= secondDistance) { extended = e; secondDistance = currentDistance + e.Weight + reversePathInfo[e.To].Dist; } } currentDistance += currentEdge.Weight; } List <Edge> pathList = new List <Edge>(); if (extended.Weight != double.PositiveInfinity) { foreach (var e in bestPath) { if (e.From == extended.From) { break; } else { pathList.Add(e); } } pathList.Add(extended); v = extended.To; while (reversePathInfo[v].Last != null) { var last = (Edge)reversePathInfo[v].Last; pathList.Add(new Edge(last.To, last.From, last.Weight)); v = last.From; } path = pathList.ToArray(); } if (path == null) { return(null); } else { return(secondDistance); } }