Пример #1
0
        /** Finding vertex-disjoint paths
         * First version uses an auxiliary directed graph, and the edge-disjoint path finding from above. **/

        // Find maximal set of vertex disjoint paths: returns the set of edges used.
        public static HashSet <Tuple <T, T> > VertexDisjointPaths <T>(this IGraphEdges <T> graph, T startVertex, T to)
        {
            if (Eq(startVertex, to) || graph.GetNeighbours(startVertex).Contains(to))
            {
                return(new HashSet <Tuple <T, T> >());
            }
            // So `startVertex` and `to` are not the same, and not neighbours
            // Build new directed graph; (t,0) is the "in" vertex for t, and (t,1) the "out" vertex.
            var transformed = new DirectedGraph <Tuple <T, int> >();

            // Make "vertex edges", except start/finish
            foreach (var v in graph.DepthFirstSearch(startVertex))
            {
                if (!Eq(startVertex, v) && !Eq(to, v))
                {
                    transformed.AddEdge(Tuple.Create(v, 0), Tuple.Create(v, 1));
                }
            }
            // Link them all up
            foreach (var vout in graph.DepthFirstSearch(startVertex))
            {
                foreach (var vin in graph.GetNeighbours(vout))
                {
                    transformed.AddEdge(Tuple.Create(vout, 1), Tuple.Create(vin, 0));
                }
            }
            var transUsedEdges = transformed.EdgeDisjointPaths(Tuple.Create(startVertex, 1), Tuple.Create(to, 0));

            // Check
            foreach (var edge in transUsedEdges)
            {
                if (Eq(edge.Item1.Item1, edge.Item2.Item1))
                {
                    if (edge.Item1.Item2 != 0 || edge.Item2.Item2 != 1)
                    {
                        throw new Exception(String.Format("Backwards edge: {0}", edge));
                    }
                }
            }

            return(new HashSet <Tuple <T, T> >(
                       from edge in transUsedEdges
                       where !Eq(edge.Item1.Item1, edge.Item2.Item1)
                       select Tuple.Create(edge.Item1.Item1, edge.Item2.Item1)));
        }
Пример #2
0
        /** Find edge-disjoint paths
         *  Uses variant of Ford-Fulkerson algorithm.
         *  See http://matthewdaws.github.io/Paths.html **/

        // Actually does the work, and returns a Set of directed edges which form the paths
        private static HashSet <Tuple <T, T> > EdgeDisjointPaths <T>(this IGraphEdges <T> graph, T startVertex, T to)
        {
            // We store the current paths as simply a list of edges used.
            var currentPaths = new HashSet <Tuple <T, T> >();

            if (Eq(startVertex, to))
            {
                return(currentPaths);
            }
            var edges = new List <Tuple <T, T> >();

            foreach (T vertex in graph.DepthFirstSearch(startVertex))
            {
                edges.Add(from end in graph.GetNeighbours(vertex) select Tuple.Create(vertex, end));
            }
            // Now apply the FF algorithm
            // Rather than build a new residual graph each time, keep a copy and update
            var residual = new DirectedGraph <T>();

            residual.AddEdges(edges);
            while (true)
            {
                var newPath = residual.FindPath(startVertex, to);
                if (newPath.Count() == 0)
                {
                    return(currentPaths); // End, so return number of paths found
                }
                // Now merge new paths into both residual graph and collection of used edges
                for (int index = 0; index < newPath.Count() - 1; ++index)
                {
                    var edge    = Tuple.Create(newPath[index], newPath[index + 1]);
                    var revEdge = Tuple.Create(newPath[index + 1], newPath[index]);
                    if (currentPaths.Contains(revEdge))
                    {
                        currentPaths.Remove(revEdge);
                        foreach (var e in graph.AsDirectedEdges(edge.Item1, edge.Item2))
                        {
                            residual.RemoveEdge(e.Item1, e.Item2);
                        }
                        foreach (var e in graph.AsDirectedEdges(revEdge.Item1, revEdge.Item2))
                        {
                            residual.AddEdge(e.Item1, e.Item2);
                        }
                    }
                    else
                    {
                        currentPaths.Add(edge);
                        foreach (var e in graph.AsDirectedEdges(edge.Item1, edge.Item2))
                        {
                            residual.RemoveEdge(e.Item1, e.Item2);
                        }
                        residual.AddEdge(revEdge.Item1, revEdge.Item2);
                    }
                }
            }
        }