protected Result CheckIfProperPath(out string message) { if (path.Length == 0) { message = "empty path returned"; return(Result.BadResult); } if (path[0].From != a) { message = "wrong starting point"; return(Result.BadResult); } if (path[path.Length - 1].To != b) { message = "wrong final point"; return(Result.BadResult); } double sum = 0; Edge last = new Edge(); bool first = true; foreach (var e in path) { if (e.From == b) { message = $"destination vertex appears inside the path"; return(Result.BadResult); } if (!g.OutEdges(e.From).Contains(e)) { message = $"edge {e} does not exist"; return(Result.BadResult); } if (first) { first = false; } else { if (e.From != last.To) { message = $"edge {last} cannot be followed by {e}"; return(Result.BadResult); } } sum += e.Weight; last = e; } if (sum != result.Value) { message = $"path does not match the length, expected {result}, is {sum}"; return(Result.BadResult); } message = "OK"; return(Result.Success); }
/// <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) { path = null; double?min = Double.MaxValue; PathsInfo[] d; Graph G; Edge edge = new Edge(); int index = 0; if (g.Directed) { G = g.Reverse(); } else { G = g; } G.DijkstraShortestPaths(b, out d); if (d[a].Dist.IsNaN()) { return(null); } Edge[] firstpath = PathsInfo.ConstructPath(b, a, d); for (int i = 0; i < firstpath.Length; i++) { int v = firstpath[i].To; foreach (Edge e in g.OutEdges(v)) { if (e.To != firstpath[i].From && d[e.To].Dist + e.Weight + d[a].Dist - d[v].Dist < min) { min = d[e.To].Dist + e.Weight + d[a].Dist - d[v].Dist; edge = e; index = i; } } } if (min == Double.MaxValue) { return(null); } Edge[] tmp = PathsInfo.ConstructPath(b, edge.To, d); Array.Reverse(tmp); for (int i = 0; i < tmp.Length; i++) { tmp[i] = new Edge(tmp[i].To, tmp[i].From, tmp[i].Weight); } path = new Edge[firstpath.Length - index + tmp.Length]; for (int i = 0; i < firstpath.Length - index - 1; i++) { path[i] = new Edge(firstpath[firstpath.Length - i - 1].To, firstpath[firstpath.Length - i - 1].From, firstpath[firstpath.Length - i - 1].Weight); } path[firstpath.Length - index - 1] = edge; Array.Copy(tmp, 0, path, firstpath.Length - index, tmp.Length); return(min); }
/// <summary> /// Algorytm znajdujący drugą pod względem długości najkrótszą ścieżkę między a i b. /// Możliwe, że jej długość jest równa najkrótszej (jeśli są dwie najkrótsze ścieżki, /// algorytm zwróci jedną z nich). /// Dopuszczamy, aby na ścieżce powtarzały się wierzchołki/krawędzie. /// Można założyć, że a!=b oraz że w grafie nie występują pętle. /// </summary> /// <remarks> /// Wymagana złożoność do O(D), gdzie D jest złożonością implementacji alogorytmu Dijkstry w bibliotece Graph. /// </remarks> /// <param name="g"></param> /// <param name="path">null jeśli druga ścieżka nie istnieje, wpp ściezka jako ciąg krawędzi</param> /// <returns>null jeśli druga ścieżka nie istnieje, wpp długość znalezionej ścieżki</returns> public static double?FindSecondShortestPath(this Graph g, int a, int b, out Edge[] path) { PathsInfo[] 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); } }