-
Notifications
You must be signed in to change notification settings - Fork 299
/
Copy pathFloyd-Warshall.cs
141 lines (115 loc) · 4.83 KB
/
Floyd-Warshall.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Collections.Generic;
using Advanced.Algorithms.DataStructures.Graph;
namespace Advanced.Algorithms.Graph;
/// <summary>
/// A floyd-warshall shortest path algorithm implementation.
/// </summary>
public class FloydWarshallShortestPath<T, TW> where TW : IComparable
{
private readonly IShortestPathOperators<TW> @operator;
public FloydWarshallShortestPath(IShortestPathOperators<TW> @operator)
{
this.@operator = @operator;
}
public List<AllPairShortestPathResult<T, TW>> FindAllPairShortestPaths(IGraph<T> graph)
{
if (@operator == null)
throw new ArgumentException("Provide an operator implementation for generic type W during initialization.");
if (!graph.IsWeightedGraph)
if (@operator.DefaultValue.GetType() != typeof(int))
throw new ArgumentException("Edges of unweighted graphs are assigned an imaginary weight of one (1)." +
"Provide an appropriate IShortestPathOperators<int> operator implementation during initialization.");
//we need this vertex array index for generics
//since array indices are int and T is unknown type
var vertexIndex = new Dictionary<int, T>();
var reverseVertexIndex = new Dictionary<T, int>();
var i = 0;
foreach (var vertex in graph.VerticesAsEnumberable)
{
vertexIndex.Add(i, vertex.Key);
reverseVertexIndex.Add(vertex.Key, i);
i++;
}
//init all distance to default Weight
var result = new TW[graph.VerticesCount, graph.VerticesCount];
//to trace the path
var parent = new T[graph.VerticesCount, graph.VerticesCount];
for (i = 0; i < graph.VerticesCount; i++)
for (var j = 0; j < graph.VerticesCount; j++)
result[i, j] = @operator.MaxValue;
for (i = 0; i < graph.VerticesCount; i++) result[i, i] = @operator.DefaultValue;
//now set the known edge weights to neighbours
for (i = 0; i < graph.VerticesCount; i++)
foreach (var edge in graph.GetVertex(vertexIndex[i]).Edges)
{
result[i, reverseVertexIndex[edge.TargetVertexKey]] = edge.Weight<TW>();
parent[i, reverseVertexIndex[edge.TargetVertexKey]] = graph.GetVertex(vertexIndex[i]).Key;
result[reverseVertexIndex[edge.TargetVertexKey], i] = edge.Weight<TW>();
parent[reverseVertexIndex[edge.TargetVertexKey], i] = edge.TargetVertexKey;
}
//here is the meat of this algorithm
//if we can reach node i to j via node k and if it is shorter pick that Distance
for (var k = 0; k < graph.VerticesCount; k++)
for (i = 0; i < graph.VerticesCount; i++)
for (var j = 0; j < graph.VerticesCount; j++)
{
//no path
if (result[i, k].Equals(@operator.MaxValue)
|| result[k, j].Equals(@operator.MaxValue))
continue;
var sum = @operator.Sum(result[i, k], result[k, j]);
if (sum.CompareTo(result[i, j]) >= 0) continue;
result[i, j] = sum;
parent[i, j] = parent[k, j];
}
//trace path
var finalResult = new List<AllPairShortestPathResult<T, TW>>();
for (i = 0; i < graph.VerticesCount; i++)
for (var j = 0; j < graph.VerticesCount; j++)
{
var source = vertexIndex[i];
var dest = vertexIndex[j];
var distance = result[i, j];
var path = TracePath(result, parent, i, j, vertexIndex, reverseVertexIndex);
finalResult.Add(new AllPairShortestPathResult<T, TW>(source, dest, distance, path));
}
return finalResult;
}
/// <summary>
/// Trace path from dest to source.
/// </summary>
private List<T> TracePath(TW[,] result, T[,] parent, int i, int j,
Dictionary<int, T> vertexIndex, Dictionary<T, int> reverseVertexIndex)
{
var pathStack = new Stack<T>();
pathStack.Push(vertexIndex[j]);
var current = parent[i, j];
while (i != j)
{
pathStack.Push(parent[i, j]);
j = reverseVertexIndex[parent[i, j]];
}
var path = new List<T>();
while (pathStack.Count > 0) path.Add(pathStack.Pop());
return path;
}
}
/// <summary>
/// All pairs shortest path algorithm result object.
/// </summary>
public class AllPairShortestPathResult<T, TW> where TW : IComparable
{
public AllPairShortestPathResult(T source, T destination,
TW distance, List<T> path)
{
Source = source;
Destination = destination;
Distance = distance;
Path = path;
}
public T Source { get; }
public T Destination { get; }
public TW Distance { get; }
public List<T> Path { get; }
}