コード例 #1
0
        public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> source) where TV : IEquatable <TV>
        {
            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>();

            // Starting point
            IVertex <TV> currentVertex = source;

            builder.AddVertex(source.Value);

            // Track which verteces have already been added to the tour, and how many edges have already been used
            HashSet <TV> visitedVerteces = new HashSet <TV>()
            {
                source.Value
            };
            int edgesUsed = 0;

            // Find and use minimum non-used edge leading from each vertex
            while (edgesUsed < graph.VertexCount)
            {
                // Last edge, select edge back to start
                if (edgesUsed == graph.VertexCount - 1)
                {
                    try
                    {
                        IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(currentVertex, source);
                        builder.AddEdge(currentVertex.Value, source.Value, closingEdge.Weight);
                    }
                    catch (VertecesNotConnectedException <TV> exception)
                    {
                        throw new GraphNotCompleteException("The NearestNeighbor algorithm expects the input graph to be complete!", exception);
                    }
                }
                else
                {
                    IWeightedEdge <TV, TW> minEdge = graph.GetEdgesOfVertex(currentVertex)
                                                     .Where(e => !visitedVerteces.Contains(e.ConnectedVertex(currentVertex).Value))
                                                     .OrderBy(e => e.Weight)
                                                     .FirstOrDefault();
                    if (minEdge == null)
                    {
                        throw new GraphNotCompleteException("The NearestNeighbor algorithm expects the input graph to be complete!");
                    }

                    // Get target vertex and update current vertex
                    IVertex <TV> target = minEdge.ConnectedVertex(currentVertex);
                    currentVertex = target;

                    // Update tracking
                    visitedVerteces.Add(target.Value);

                    // Update result graph
                    builder.AddVertex(target.Value);
                    builder.AddEdge(source.Value, target.Value, minEdge.Weight);
                }
                edgesUsed++;
            }

            // Done: used n-1 edges for n verteces
            return(builder.Build());
        }
コード例 #2
0
ファイル: BellmanFordMoore.cs プロジェクト: alex-c/Graft
        public static IWeightedGraph <TV, TW> FindShortestPath <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                        IVertex <TV> source,
                                                                        IVertex <TV> target,
                                                                        TW zeroValue,
                                                                        TW maxValue,
                                                                        Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable
        {
            Dictionary <IVertex <TV>, TW> distance = new Dictionary <IVertex <TV>, TW>();
            Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor = new Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> >();

            // Initialize distance and predecessor maps
            foreach (IVertex <TV> vertex in graph.GetAllVerteces())
            {
                distance.Add(vertex, maxValue);
                predecessor.Add(vertex, null);
            }
            distance[source] = zeroValue;

            // Relax edges repeatedly
            IEnumerable <IWeightedEdge <TV, TW> > edges = graph.GetAllEdges();

            for (int i = 0; i < graph.VertexCount - 1; i++)
            {
                foreach (IWeightedEdge <TV, TW> edge in edges)
                {
                    if (graph.IsDirected)
                    {
                        try
                        {
                            IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge;
                            RelaxEdge(distance, predecessor, directedEdge.OriginVertex, directedEdge.TargetVertex, directedEdge.Weight, directedEdge, combineCosts);
                        }
                        catch
                        {
                            throw new Exception("Failed casting edge to directed edge for directed graph.");
                        }
                    }
                    else
                    {
                        IVertex <TV> sourceVertex = edge.Verteces.First();
                        IVertex <TV> targetVertex = edge.ConnectedVertex(sourceVertex);
                        RelaxEdge(distance, predecessor, sourceVertex, targetVertex, edge.Weight, edge, combineCosts);
                        RelaxEdge(distance, predecessor, targetVertex, sourceVertex, edge.Weight, edge, combineCosts);
                    }
                }
            }

            // Check for negative - weight cycles
            foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges())
            {
                if (graph.IsDirected)
                {
                    IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge;
                    CheckForNegativeCycles(distance, directedEdge.OriginVertex, directedEdge.TargetVertex, directedEdge.Weight, combineCosts);
                }
                else
                {
                    IVertex <TV> sourceVertex = edge.Verteces.First();
                    IVertex <TV> targetVertex = edge.ConnectedVertex(sourceVertex);
                    CheckForNegativeCycles(distance, sourceVertex, targetVertex, edge.Weight, combineCosts);
                    CheckForNegativeCycles(distance, targetVertex, sourceVertex, edge.Weight, combineCosts);
                }
            }

            // Build and output path
            IVertex <TV>          currentVertex = target;
            GraphBuilder <TV, TW> builder       = new GraphBuilder <TV, TW>(true).AddVertex(target.Value);

            while (currentVertex != source)
            {
                IWeightedEdge <TV, TW> pathEdge       = predecessor[currentVertex];
                IVertex <TV>           previousVertex = pathEdge.ConnectedVertex(currentVertex);
                builder
                .AddVertex(previousVertex.Value)
                .AddEdge(previousVertex.Value, currentVertex.Value, pathEdge.Weight);
                currentVertex = previousVertex;
            }
            return(builder.Build());
        }
コード例 #3
0
        public static IWeightedGraph <TV, TW> FindShortestPath <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                        IVertex <TV> source,
                                                                        IVertex <TV> target,
                                                                        TW zeroValue,
                                                                        TW maxValue,
                                                                        Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable
        {
            HashSet <IVertex <TV> >           visitedVerteces = new HashSet <IVertex <TV> >();
            IPriorityQueue <IVertex <TV>, TW> vertecesToVisit = new NaivePriorityQueue <IVertex <TV>, TW>();
            Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor = new Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> >();

            // Initialize queue and predecessor map
            foreach (IVertex <TV> vertex in graph.GetAllVerteces())
            {
                vertecesToVisit.Enqueue(vertex, maxValue);
                predecessor.Add(vertex, null);
            }
            vertecesToVisit.UpdatePriority(source, zeroValue);

            // Continue as long as there are verteces to visit
            IVertex <TV> currentVertex = null;
            TW           currentCosts  = zeroValue;

            while (!vertecesToVisit.Empty)
            {
                // Get the closest next vertex
                (currentVertex, currentCosts) = vertecesToVisit.Dequeue();

                // Check whether we reached our target
                if (currentVertex == target)
                {
                    break;
                }
                visitedVerteces.Add(currentVertex);

                // If not, discover the next verteces that can be visited
                foreach (IWeightedEdge <TV, TW> edge in graph.GetEdgesOfVertex(currentVertex))
                {
                    if (edge.Weight.CompareTo(zeroValue) < 0)
                    {
                        throw new NegativeEdgeWeightException();
                    }
                    IVertex <TV> connectedVertex = edge.ConnectedVertex(currentVertex);
                    if (!visitedVerteces.Contains(connectedVertex))
                    {
                        TW newCosts = combineCosts(currentCosts, edge.Weight);
                        if (newCosts.CompareTo(vertecesToVisit.GetPriorityOf(connectedVertex)) < 0)
                        {
                            vertecesToVisit.UpdatePriority(connectedVertex, newCosts);
                            predecessor[connectedVertex] = edge;
                        }
                    }
                }
            }

            // If we reached the target vertex, build result graph
            if (currentVertex == target)
            {
                GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(true).AddVertex(target.Value);
                while (currentVertex != source)
                {
                    IWeightedEdge <TV, TW> pathEdge       = predecessor[currentVertex];
                    IVertex <TV>           previousVertex = pathEdge.ConnectedVertex(currentVertex);
                    builder
                    .AddVertex(previousVertex.Value)
                    .AddEdge(previousVertex.Value, currentVertex.Value, pathEdge.Weight);
                    currentVertex = previousVertex;
                }
                return(builder.Build());
            }
            else
            {
                throw new VertexNotReachableException <TV>(target);
            }
        }
コード例 #4
0
        /// <summary>
        /// Builds the minimum spanning tree of a given graph.
        /// </summary>
        /// <typeparam name="TV">Type of the graph vertex values.</typeparam>
        /// <typeparam name="TW">Type of the graph edge weights.</typeparam>
        /// <param name="graph">The graph got which to build the minimum spanning tree.</param>
        /// <returns>Returns the minimum spanning tree of the given graph.</returns>
        public static IWeightedGraph <TV, TW> FindMinimumSpanningTree <TV, TW>(IWeightedGraph <TV, TW> graph, TW min, TW max)
            where TV : IEquatable <TV>
            where TW : IComparable
        {
            // Builder used to incrementally build the target minimum spanning tree
            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>();

            // Get all verteces and edges of graph
            IEnumerable <IVertex <TV> >           verteces = graph.GetAllVerteces();
            IEnumerable <IWeightedEdge <TV, TW> > edges    = graph.GetAllEdges();

            // TODO: replace with more performant priority queue implementation
            // Track minimum known cost to connect to target vertex
            IPriorityQueue <TV, TW> vertexCosts = new NaivePriorityQueue <TV, TW>();

            // Track target vertex and edge connecting to target vertex with minimum known cost
            Dictionary <TV, IVertex <TV> >           vertexValue = new Dictionary <TV, IVertex <TV> >();
            Dictionary <TV, IWeightedEdge <TV, TW> > vertexEdges = new Dictionary <TV, IWeightedEdge <TV, TW> >();

            // Initialize vertex costs with all costs set to max
            foreach (IVertex <TV> vertex in verteces)
            {
                vertexCosts.Enqueue(vertex.Value, max);
                vertexValue.Add(vertex.Value, vertex);
                vertexEdges.Add(vertex.Value, null);
            }

            // Set starting vertex
            vertexCosts.UpdatePriority(verteces.First().Value, min);

            // While there are verteces left to add, select vertex with smallest cost
            while (!vertexCosts.Empty)
            {
                // Get and remove vertex with smallest cost
                TV minCost = vertexCosts.Dequeue().Item1;

                // For easier handling, get vertex and edge
                IVertex <TV>           vertex = vertexValue[minCost];
                IWeightedEdge <TV, TW> edge   = vertexEdges[minCost];

                // Add vertex and edge to target MST
                builder.AddVertex(vertex.Value);
                if (edge != null)
                {
                    builder.AddEdge(vertex.Value, edge.ConnectedVertex(vertex.Value).Value, edge.Weight);
                }

                // Update vertex cost for adjacent verteces and store edges
                foreach (IWeightedEdge <TV, TW> connectedEdge in graph.GetEdgesOfVertex(vertex))
                {
                    // Ignore edges leading to verteces already added to the MST
                    IVertex <TV> targetVertex = connectedEdge.ConnectedVertex(vertex);
                    if (vertexCosts.Contains(targetVertex.Value) &&
                        connectedEdge.Weight.CompareTo(vertexCosts.GetPriorityOf(targetVertex.Value)) < 0)
                    {
                        vertexCosts.UpdatePriority(targetVertex.Value, connectedEdge.Weight);
                        vertexEdges[targetVertex.Value] = connectedEdge;
                    }
                }
            }

            // All verteces added to MST - done!
            return(builder.Build());
        }