/// <summary> /// <para><paramref name="from"/> からの最短経路長をベルマン・フォード法で求める。負の長さにも使える</para> /// <para>計算量: O(|V|・|E|)</para> /// </summary> public static T[] BellmanFord <T, TOp, TNode, TEdge>(this IWGraph <T, TOp, TNode, TEdge> graph, int from) where T : struct where TOp : struct, INumOperator <T> where TNode : IGraphNode <TEdge> where TEdge : IWGraphEdge <T> { TOp op = default; var graphArr = graph.AsArray(); var INF = op.Divide(op.MaxValue, op.Increment(op.MultiplyIdentity)); var res = new T[graphArr.Length]; Array.Fill(res, INF); res[from] = default; for (int i = 1; i <= graphArr.Length; i++) { foreach (var node in graphArr) { foreach (var e in node.Children) { var to = e.To; var x = op.Add(res[node.Index], e.Value); if (op.GreaterThan(res[to], x)) { res[to] = x; if (i == graphArr.Length) { throw new InvalidOperationException("負の閉路"); } } } } } return(res); }
/// <summary> /// <para><paramref name="from"/> からの最短経路長を01-BSFで求める。</para> /// <para>計算量: O(|E| + |V|)</para> /// </summary> public static T[] ShortestPath01BFS <T, TOp, TNode, TEdge>(this IWGraph <T, TOp, TNode, TEdge> graph, int from) where T : struct where TOp : struct, INumOperator <T> where TNode : IGraphNode <TEdge> where TEdge : IWGraphEdge <T> { TOp op = default; var graphArr = graph.AsArray(); var INF = op.MaxValue; var res = new T[graphArr.Length]; System.Array.Fill(res, INF); res[from] = default; var used = new bool[graphArr.Length]; int count = 0; var remains = new Deque <int>(graphArr.Length) { from }; while (remains.Count > 0) { var ix = remains.PopFirst(); if (used[ix]) { continue; } used[ix] = true; if (++count >= graphArr.Length) { break; } var len = res[ix]; foreach (var e in graphArr[ix].Children) { var to = e.To; var nextLength = len; if (EqualityComparer <T> .Default.Equals(e.Value, default)) { if (op.GreaterThan(res[to], nextLength)) { res[to] = nextLength; remains.AddFirst(to); } } else { nextLength = op.Increment(nextLength); if (op.GreaterThan(res[to], nextLength)) { res[to] = nextLength; remains.AddLast(to); } } } } return(res); }
private static Dictionary <NodeType, NodeType> DijekstraBuilder <NodeType>(IWGraph <NodeType> graph, NodeType source) { Dictionary <NodeType, int> graphCurrW = new Dictionary <NodeType, int>(); Dictionary <NodeType, NodeType> Fathers = new Dictionary <NodeType, NodeType>(); Dictionary <NodeType, bool> visted = new Dictionary <NodeType, bool>(); List <NodeType> Mins = new List <NodeType>(); Mins.Add(source); graphCurrW.Add(source, 0); while (Mins.Count != 0) { NodeType currNode = Mins[0]; if (!visted.ContainsKey(currNode)) { visted.Add(currNode, true); Mins.RemoveAt(0); foreach (var neighbor in graph.Neighbors(currNode)) { if (graphCurrW.ContainsKey(neighbor)) { // Debug.Log("27"); if (graphCurrW[neighbor] > graphCurrW[currNode] + graph.Weight(neighbor)) { // Debug.Log("30"); graphCurrW[neighbor] = graphCurrW[currNode] + graph.Weight(neighbor); // Debug.Log("32"); Fathers[neighbor] = currNode; if (!visted.ContainsKey(neighbor)) { // Debug.Log("36"); Mins.Insert(getPosInArray(Mins, graphCurrW[neighbor], graph), neighbor); } } } else { // Debug.Log("44"); graphCurrW[neighbor] = graphCurrW[currNode] + graph.Weight(neighbor); // Debug.Log("46"); Fathers[neighbor] = currNode; if (!visted.ContainsKey(neighbor)) { // Debug.Log("50"); Mins.Insert(getPosInArray(Mins, graphCurrW[neighbor], graph), neighbor); } } } } else { Mins.RemoveAt(0); } } return(Fathers); }
/// <summary> /// <para><paramref name="from"/> からの最短経路長をダイクストラ法で求める。</para> /// <para>計算量: O( (|E| + |V|) log |V| )</para> /// </summary> public static T[] Dijkstra <T, TOp, TNode, TEdge>(this IWGraph <T, TOp, TNode, TEdge> graph, int from) where T : struct where TOp : struct, INumOperator <T> where TNode : IGraphNode <TEdge> where TEdge : IWGraphEdge <T> { TOp op = default; var graphArr = graph.AsArray(); var INF = op.MaxValue; var res = new T[graphArr.Length]; System.Array.Fill(res, INF); res[from] = default; var used = new bool[graphArr.Length]; int count = 0; var remains = new PriorityQueueDijkstra <T, TOp>(graphArr.Length); remains.Enqueue(default, from);
public static List <NodeType> GetPath <NodeType>(IWGraph <NodeType> graph, NodeType source, NodeType dest) { List <NodeType> path = new List <NodeType>(); Dictionary <NodeType, NodeType> route = DijekstraBuilder(graph, source); //Checking the destination node exists in the possible paths if (route.ContainsKey(dest)) { NodeType tempD = dest; path.Insert(0, tempD); //creating the list for the path while (!path[0].Equals(source)) { tempD = route[tempD]; path.Insert(0, tempD); } } return(path); }
public static List <NodeType> GetPath <NodeType>(IWGraph <NodeType> graph, NodeType source, NodeType dest) { List <NodeType> path = new List <NodeType>(); Dictionary <NodeType, NodeType> route = DijekstraBuilder(graph, source); if (route.ContainsKey(dest)) { NodeType tempD = dest; path.Insert(0, tempD); // while (!path[0].Equals(source)) { //Debug.Log("END?"); tempD = route[tempD]; path.Insert(0, tempD); } // Debug.Log("return"); } return(path); }
/// <summary> /// <para>各頂点間の最短経路長をワーシャルフロイド法で求める</para> /// <para>計算量: O(|V|^3)</para> /// </summary> public static T[][] WarshallFloyd <T, TOp, TNode, TEdge>(this IWGraph <T, TOp, TNode, TEdge> graph) where T : struct where TOp : struct, INumOperator <T> where TNode : IGraphNode <TEdge> where TEdge : IWGraphEdge <T> { TOp op = default; var graphArr = graph.AsArray(); var INF = op.Divide(op.MaxValue, op.Increment(op.MultiplyIdentity)); var res = new T[graphArr.Length][]; for (var i = 0; i < graphArr.Length; i++) { res[i] = new T[graphArr.Length]; System.Array.Fill(res[i], INF); res[i][i] = default; foreach (var e in graphArr[i].Children) { res[i][e.To] = e.Value; } } for (var k = 0; k < graphArr.Length; k++) { for (var i = 0; i < graphArr.Length; i++) { for (var j = 0; j < graphArr.Length; j++) { var x = op.Add(res[i][k], res[k][j]); if (op.GreaterThan(res[i][j], x)) { res[i][j] = x; } } } } return(res); }
private static int getPosInArray <NodeType>(List <NodeType> Mins, int destNodeW, IWGraph <NodeType> graph) { int minIndex = 0; int maxIndex = Mins.Count - 1; int middle = minIndex + (maxIndex - minIndex) / 2; while (minIndex <= maxIndex) { if (graph.Weight(Mins[middle]) == destNodeW) { return(middle); } if (destNodeW > graph.Weight(Mins[middle])) { minIndex = middle + 1; } if (destNodeW < graph.Weight(Mins[middle])) { maxIndex = middle - 1; } middle = minIndex + (maxIndex - minIndex) / 2; } return(middle); }
//A Dijkstra building algorithm, returns a Dictionary of paths private static Dictionary <NodeType, NodeType> DijekstraBuilder <NodeType>(IWGraph <NodeType> graph, NodeType source) { //Current weights for each visited node Dictionary <NodeType, int> graphCurrW = new Dictionary <NodeType, int>(); //"Fathers" of each nodes, needed to find the path back Dictionary <NodeType, NodeType> Fathers = new Dictionary <NodeType, NodeType>(); //Marking nodes that are done Dictionary <NodeType, bool> visted = new Dictionary <NodeType, bool>(); //List of Nodes needed to visit. A sorted list from minimum weight to maximum weight. List <NodeType> Mins = new List <NodeType>(); // Adding the source node Mins.Add(source); // Setting first node weight to 0 graphCurrW.Add(source, 0); // Running while we have any node to work on while (Mins.Count != 0) { //Taking the minimum weighted node from the list NodeType currNode = Mins[0]; //Making sure that this node is not yet worked on if (!visted.ContainsKey(currNode)) { //Adding this node to visited nodes, which means we don't need to work on it anymore visted.Add(currNode, true); //Removing it from the list of nodes Mins.RemoveAt(0); foreach (var neighbor in graph.Neighbors(currNode)) { //Checking if we have "worked" on the node previously if (graphCurrW.ContainsKey(neighbor)) { //Checking if the current weight is higher then new weight if (graphCurrW[neighbor] > graphCurrW[currNode] + graph.Weight(neighbor)) { //Set new weight graphCurrW[neighbor] = graphCurrW[currNode] + graph.Weight(neighbor); //Set the new father of the node Fathers[neighbor] = currNode; //if the neighbor is not yet worked on then add it the nodes that need to be worked on if (!visted.ContainsKey(neighbor)) { //add the node in a position to keep the list sorted Mins.Insert(getPosInArray(Mins, graphCurrW[neighbor], graph), neighbor); } } } else { //if its a new node completely set weights and father graphCurrW[neighbor] = graphCurrW[currNode] + graph.Weight(neighbor); Fathers[neighbor] = currNode; if (!visted.ContainsKey(neighbor)) { Mins.Insert(getPosInArray(Mins, graphCurrW[neighbor], graph), neighbor); } } } } else { //remove nodes that we don't need to work on Mins.RemoveAt(0); } } return(Fathers); }