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); }