Esempio n. 1
0
        private static IEnumerable <V> ReversePostOrder <V>(DiGraph <V> graph)
        {
            var visited = new HashSet <V>();
            var stack   = new LinkedList <V>();

            void Go(V v)
            {
                visited.Add(v);
                var neighbours = graph.Edges(v).Select(e => e.to);

                foreach (var w in neighbours)
                {
                    if (!visited.Contains(w))
                    {
                        Go(w);
                    }
                }
                stack.Push(v);
            }

            // Account for the fact that:
            // - Not all vertices are reachable from one another
            // - The vertex we call Go on first might have incoming links
            foreach (var v in graph.Vertices())
            {
                if (!visited.Contains(v))
                {
                    Go(v);
                }
            }

            return(stack);
        }
Esempio n. 2
0
        /// <summary>
        /// Solves the single-source shortest path problem in O(E*ln V) time for a graph with none-negative edge weights.
        /// </summary>
        public static Paths <V> Dijkstra <V>(DiGraph <V> graph, V source) where V : class
        {
            if (graph == null || source == null)
            {
                throw new ArgumentNullException();
            }

            if (!graph.Contains(source))
            {
                throw new ArgumentException();
            }

            if (graph.Edges().Any(e => e.weight < 0))
            {
                throw new ArgumentException();
            }

            var queue  = new BinaryHeap <Double, V>();
            var distTo = new HashMap <V, Double>();
            var edgeTo = new HashMap <V, Edge <V> >();

            void Relax(Edge <V> e)
            {
                var(v, w) = (e.from, e.to);
                var weight = new Double(e.weight);

                if (distTo[v] > distTo[w] + weight)
                {
                    distTo[w] = distTo[v] + weight;
                    edgeTo[w] = e;
                    if (queue.Contains(w))
                    {
                        queue.Update(w, distTo[w]);
                    }
                    else
                    {
                        queue.Push(w, distTo[w]);
                    }
                }
            }

            foreach (var v in graph.Vertices())
            {
                distTo[v] = Double.MaxValue;
            }
            distTo[source] = new Double(0);

            queue.Push(source, new Double(0));

            while (!queue.IsEmpty())
            {
                var(_, v) = queue.Pop();
                foreach (var e in graph.Edges(v))
                {
                    Relax(e);
                }
            }
            return(new Paths <V>(source, edgeTo));
        }
Esempio n. 3
0
        /// <summary>
        /// Returns all the strongly connected components that comprise this <c>graph</c> in O(V+E) time.
        /// </summary>
        /// <returns>A set containing each strongly connected component, represented as a subgraph</returns>
        public static ISet <DiGraph <V> > Components <V>(DiGraph <V> graph)
        {
            if (graph == null)
            {
                throw new ArgumentNullException();
            }

            // Kosaraju-Sharir algorithm
            // 1. Return vertices of G^R in reverse postorder
            // 2. Run DFS on G, visiting unmarked vertices in the order above

            // 1.
            var reversed = ReversePostOrder(graph.Complement());

            // 2.
            var visited = new HashSet <V>();

            // Creates and returns a subgraph containing vertices reachable by s only
            DiGraph <V> Component(V s)
            {
                var g     = new DiGraph <V>();
                var stack = new LinkedList <V>();

                stack.Push(s);

                while (!stack.IsEmpty())
                {
                    var v = stack.Pop();
                    visited.Add(v);
                    foreach (var e in graph.Edges(v))
                    {
                        var w = e.to;
                        if (visited.Contains(w))
                        {
                            continue;  // w is already part of THIS component
                        }
                        graph.Add(e);
                        stack.Push(w);
                    }
                }

                return(g);
            }

            var components = new HashSet <DiGraph <V> >();

            foreach (var v in reversed)
            {
                if (visited.Contains(v))
                {
                    continue;  // v is part of a component that has already been created
                }
                components.Add(Component(v));
            }

            return(components);
        }
Esempio n. 4
0
        /// <summary>
        /// Returns all the vertices of this graph in topological order in O(V+E) time.
        /// Raises <exception cref="System.InvalidOperationException"> if the graph is cyclic.
        /// </summary>
        public static IEnumerable <V> TopologicalSort <V>(DiGraph <V> graph)
        {
            if (graph == null)
            {
                throw new ArgumentNullException();
            }

            // A digraph containing a directed cycle cannot be topologically ordered
            if (graph.IsCyclic())
            {
                throw new InvalidOperationException();
            }

            // In topological order v preceedes w for an edge v -> w.
            // The reversed output of a postorder DFS trace can be useds to perform topological sorting of vertices.

            return(ReversePostOrder(graph));
        }
Esempio n. 5
0
        /// <summary>
        /// Solves the single-source shortest path problem in O(E*V) time for a graph without any negative cycles, or in O(V+E) time if it is a DAG.
        /// </summary>
        public static Paths <V> BellmanFord <V>(DiGraph <V> graph, V source)
        {
            if (graph == null || source == null)
            {
                throw new ArgumentNullException();
            }

            if (!graph.Contains(source))
            {
                throw new ArgumentException();
            }

            var distTo = new HashMap <V, Double>();
            var edgeTo = new HashMap <V, Edge <V> >();

            bool Relax(Edge <V> e)
            {
                var(v, w) = (e.from, e.to);
                var weight = new Double(e.weight);

                if (distTo[v] > distTo[w] + weight)
                {
                    distTo[w] = distTo[v] + weight;
                    edgeTo[w] = e;
                    return(true);
                }
                return(false);
            }

            foreach (var v in graph.Vertices())
            {
                distTo[v] = Double.MaxValue;
            }
            distTo[source] = new Double(0);

            // The Bellman Ford procedure involves relaxing every edge V times.
            // However, for a DAG we can delegate to a simpler algorithm that runs in linear time

            try
            {
                var vertices = TopologicalSort(graph);
                foreach (var v in vertices)
                {
                    foreach (var e in graph.Edges(v))
                    {
                        Relax(e);
                    }
                }
            }
            catch (InvalidOperationException)
            {
                // Graph is not a DAG
                var N = graph.Size();
                foreach (var i in Enumerable.Range(1, N))
                {
                    foreach (var e in graph.Edges())
                    {
                        var relaxed = Relax(e);
                        if (i == N && relaxed)
                        {
                            throw new InvalidOperationException("Negative cycle detected");
                        }
                    }
                }
            }

            return(new Paths <V>(source, edgeTo));
        }