Exemplo 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);
        }
Exemplo 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));
        }
Exemplo n.º 3
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));
        }