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