// Call with `paths` being a family of paths from startVertex to some end point. This family should // be vertex-disjoint and maximal. // Returns a cut. public static List <T> FindCutVDP <T>(this IGraphEdges <T> graph, T startVertex, List <List <T> > paths) { var usedEdges = new HashSet <Tuple <T, T> >(); foreach (var path in paths) { for (int i = 0; i < path.Count() - 1; ++i) { usedEdges.Add(Tuple.Create(path[i], path[i + 1])); } } var accessible = new HashSet <T>(from pair in graph.AccessibleVerticesVDP(startVertex, usedEdges) select pair.Item1); var cut = new HashSet <T>( from vertex in accessible from v in graph.GetNeighbours(vertex) where !accessible.Contains(v) select vertex); if (cut.Remove(startVertex)) { foreach (var v in graph.GetNeighbours(startVertex)) { if (!accessible.Contains(v)) { cut.Add(v); } } } return(new List <T>(cut)); }
// Variant which allows us to start with some existing paths: useful if e.g. the application // comes with some "obvious" paths we can start from. This assumes that `startVertex` and `to` // are not equal or neighbours. public static List <List <T> > FindVertexDisjointPaths1 <T>(this IGraphEdges <T> graph, T startVertex, T to, HashSet <Tuple <T, T> > edges) { var usedEdges = new HashSet <Tuple <T, T> >(edges); while (true) { // newPath[vertex] == predecessor of vertex; i.e. edge from newPath[vertex] to vertex var lookup = new Dictionary <T, T>(); // Problem: It's possible to visit the same vertex twice (thanks to non-local walking rules) var backup = new Dictionary <T, T>(); bool canReachTo = false; foreach (var vertexPair in graph.AccessibleVerticesVDP(startVertex, usedEdges)) { // Edge from vertexPair.Item2 to vertexPair.Item1 if (Eq(startVertex, vertexPair.Item1)) { continue; } if (lookup.ContainsKey(vertexPair.Item1)) { backup[vertexPair.Item1] = lookup[vertexPair.Item1]; } lookup[vertexPair.Item1] = vertexPair.Item2; if (Eq(to, vertexPair.Item1)) { canReachTo = true; break; } } if (!canReachTo) { break; } var vertex = to; while (!Eq(vertex, startVertex)) { var edge = Tuple.Create(lookup[vertex], vertex); var revEdge = Tuple.Create(vertex, lookup[vertex]); if (!usedEdges.Remove(revEdge)) { usedEdges.Add(edge); } if (backup.ContainsKey(vertex)) { T tmp = lookup[vertex]; lookup[vertex] = backup[vertex]; vertex = tmp; } else { vertex = lookup[vertex]; } } } // Assemble Paths return(ConvertEdgesToPaths(usedEdges, startVertex, to)); }