Ejemplo n.º 1
0
        public void GraphWithOptions()
        {
            var g = new TestGraph(Enumerable.Range(1, 6).ToArray())
            {
                { 1, new[] { 2 } },
                { 2, new[] { 4 } },
                { 3, new[] { 4, 6 } },
                { 4 },
                { 5, new[] { 6 } },
                { 6 },
            };

            g.AddEdge(2, 3, 1);
            g.AddEdge(3, 5, 1);

            var spGraph = ShortestPathGraphWithOptions.Build(g, edge => edge.IsFree || edge.MustUseOption, new[] { 1 }, 1);
            var testShortestPathGraph = new TestShortestPathGraph
            {
                { 1, 0, new[] { 2 } },
                { 2, 1, new[] { 4, 3 } },
                { 3, 2, new[] { 5, 6 } },
                { 4, 2, null, new[] { 3 } },
                { 5, 4 },
                { 6, 3, new[] { 5 } },
            };

            testShortestPathGraph[2].Edges.Single(e => e.To == 3).River.Owner = 1;
            testShortestPathGraph[3].Edges.Single(e => e.To == 5).River.Owner = 1;
            spGraph.ShouldBeEquivalentTo(testShortestPathGraph);
        }
        public static ShortestPathGraphWithOptions Build(Graph graph, Func <Edge, bool> takeEdge, ICollection <int> sourceVertexes, int optionsCount)
        {
            var queue = new SortedSet <QueueItem>();
            var dist  = CreateMap(new { OptionsUsed = 0, VertexId = 0 }, 0);

            foreach (var sourceVertex in sourceVertexes)
            {
                queue.Add(new QueueItem(0, 0, sourceVertex));
                dist[new { OptionsUsed = 0, VertexId = sourceVertex }] = 0;
            }

            while (queue.Any())
            {
                var item = queue.Min();
                queue.Remove(item);
                var from = item.VertexId;
                if (dist[new { item.OptionsUsed, item.VertexId }] != item.Distance)
                {
                    continue;
                }
                foreach (var edge in graph.Vertexes[from].Edges)
                {
                    if (!takeEdge(edge))
                    {
                        continue;
                    }
                    var to          = edge.To;
                    var nextOptions = item.OptionsUsed + (edge.MustUseOption ? 1 : 0);
                    if (nextOptions > optionsCount)
                    {
                        continue;
                    }
                    var newDistance = item.Distance + 1;
                    if (dist.TryGetValue(new { OptionsUsed = nextOptions, VertexId = to }, out var curDistance) && curDistance <= newDistance)
                    {
                        continue;
                    }

                    dist[new { OptionsUsed = nextOptions, VertexId = to }] = newDistance;
                    queue.Add(new QueueItem(nextOptions, newDistance, to));
                }
            }

            var spGraph         = new ShortestPathGraphWithOptions();
            var vertexDistances = dist.GroupBy(x => x.Key.VertexId)
                                  .ToDictionary(distances => distances.Key, distances => distances.Min(d => d.Value));

            foreach (var item in vertexDistances)
            {
                spGraph.AddVertex(item.Key, item.Value);
            }
            foreach (var from in spGraph.Vertexes.Values)
            {
                foreach (var edge in graph.Vertexes[from.Id].Edges)
                {
                    var to = spGraph[edge.To];
                    if (to.Distance == -1)
                    {
                        continue;
                    }
                    if (to.Distance == from.Distance && from.Id < to.Id)
                    {
                        spGraph.AddSameLayerEdge(edge);
                    }
                    if (to.Distance > from.Distance)
                    {
                        spGraph.AddEdge(edge);
                    }
                }
            }

            return(spGraph);
        }