Created
January 21, 2021 00:00
-
-
Save JerryNixon/df68ec2053ef5af8da69855c030cf95e to your computer and use it in GitHub Desktop.
Simple implementation of Floyd-Warshall in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Diagnostics; | |
| using System.Linq; | |
| namespace Algo | |
| { | |
| internal class Program | |
| { | |
| public static void Main() | |
| { | |
| var s = new Stopwatch(); | |
| var count = 0; | |
| var data = Generate(); | |
| var matrix = CreateMatrix(data.Nodes, data.Edges); | |
| PrintMatrix(matrix, "Original"); | |
| Run(s, out data, out matrix); | |
| PrintMatrix(matrix, "Final"); | |
| void Run(Stopwatch s, out (string[] Nodes, SimpleEdge[] Edges) data, out MatrixItem[] matrix) | |
| { | |
| data = Generate(); | |
| matrix = CreateMatrix(data.Nodes, data.Edges); | |
| s.Reset(); | |
| s.Start(); | |
| FloydWarshall(ref matrix); | |
| Console.WriteLine($"{s.Elapsed} {++count} RUN"); | |
| } | |
| } | |
| private static void FloydWarshall(ref MatrixItem[] matrix) | |
| { | |
| var nodes = matrix.Select(x => x.From).Union(matrix.Select(x => x.To)).ToArray(); | |
| foreach (var k in nodes) | |
| { | |
| foreach (var i in nodes) | |
| { | |
| foreach (var j in nodes.Where(x => x != i)) | |
| { | |
| var i_k = matrix.Single(x => x.From == i && x.To == k); | |
| var k_j = matrix.Single(x => x.From == k && x.To == j); | |
| var i_j = matrix.Single(x => x.From == i && x.To == j); | |
| // relaxation step | |
| if (i_k.Cost + k_j.Cost < i_j.Cost) | |
| { | |
| i_j.Cost = i_k.Cost + k_j.Cost; | |
| i_j.AddPath(i_k.Path.Split(";").Concat(k_j.Path.Split(";")).ToArray()); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| private static void PrintMatrix(IEnumerable<MatrixItem> matrix, string title) | |
| { | |
| Console.WriteLine(); | |
| Console.WriteLine(title.PadLeft(10)); | |
| var size = 20; | |
| var nodes = matrix.Select(x => x.From).Union(matrix.Select(x => x.To)).Distinct(); | |
| Console.Write(string.Empty.PadLeft(size)); | |
| foreach (var item in nodes) | |
| { | |
| Console.Write(item.PadLeft(size)); | |
| } | |
| Console.WriteLine(); | |
| Console.Write(".".PadLeft(size)); | |
| Console.Write(new String('-', nodes.Count() * size)); | |
| Console.WriteLine(); | |
| foreach (var i in nodes) | |
| { | |
| // print cost | |
| Console.Write($"{i} |".PadLeft(size)); | |
| foreach (var j in nodes) | |
| { | |
| var item = matrix.SingleOrDefault(x => x.From == i && x.To == j); | |
| if (item is null) | |
| { | |
| Console.Write($"{i}>{j}".PadLeft(size)); | |
| } | |
| else if (i == j) | |
| { | |
| Console.Write("-".PadLeft(size)); | |
| } | |
| else if (item.Cost == double.MaxValue) | |
| { | |
| Console.Write("-".PadLeft(size)); | |
| } | |
| else if (item.Cost is null) | |
| { | |
| Console.Write("INVALID".PadLeft(size)); | |
| } | |
| else | |
| { | |
| Console.Write(item.Cost.Value.ToString("C2").PadLeft(size)); | |
| } | |
| } | |
| Console.WriteLine(); | |
| Console.Write($"{i} |".PadLeft(size)); | |
| foreach (var j in nodes) | |
| { | |
| var item = matrix.SingleOrDefault(x => x.From == i && x.To == j); | |
| if (item.Cost == double.MaxValue | item is null | i == j) | |
| { | |
| Console.Write("-".PadLeft(size)); | |
| } | |
| else | |
| { | |
| Console.Write(item.ToString().PadLeft(size)); | |
| } | |
| } | |
| Console.WriteLine(); | |
| } | |
| Console.WriteLine(); | |
| } | |
| public static MatrixItem[] CreateMatrix(IEnumerable<string> nodes, IEnumerable<SimpleEdge> edges) | |
| { | |
| var mix = nodes.Union(edges.Select(x => x.From)).Union(edges.Select(x => x.To)).Distinct(); | |
| return mix.SelectMany(x => mix.Select(y => new MatrixItem(x, y, DetermineCost(x, y)))).ToArray(); | |
| double? DetermineCost(string x, string y) | |
| { | |
| if (x == y) | |
| { | |
| return double.MaxValue; | |
| } | |
| var cost = edges.SingleOrDefault(z => z.From == x && z.To == y)?.Cost; | |
| if (cost is null) | |
| { | |
| return double.MaxValue; | |
| } | |
| return cost; | |
| } | |
| } | |
| public static (string[] Nodes, SimpleEdge[] Edges) Generate() | |
| { | |
| var nodes = new[] { "A", "B", "C", "D", "E" }; | |
| var edges = new[] | |
| { | |
| new SimpleEdge{ From = "A", To = "B", Cost = 10 }, | |
| new SimpleEdge{ From = "A", To = "C", Cost = 01 }, | |
| new SimpleEdge{ From = "A", To = "D", Cost = 10 }, | |
| new SimpleEdge{ From = "A", To = "E", Cost = 10 }, | |
| new SimpleEdge{ From = "B", To = "B", Cost = 10 }, | |
| new SimpleEdge{ From = "B", To = "C", Cost = 10 }, | |
| new SimpleEdge{ From = "B", To = "D", Cost = 01 }, | |
| new SimpleEdge{ From = "B", To = "E", Cost = 10 }, | |
| new SimpleEdge{ From = "C", To = "A", Cost = 01 }, | |
| new SimpleEdge{ From = "C", To = "B", Cost = 01 }, | |
| new SimpleEdge{ From = "C", To = "C", Cost = 10 }, | |
| new SimpleEdge{ From = "C", To = "D", Cost = 10 }, | |
| new SimpleEdge{ From = "C", To = "E", Cost = 10 }, | |
| new SimpleEdge{ From = "D", To = "B", Cost = 10 }, | |
| new SimpleEdge{ From = "D", To = "C", Cost = 10 }, | |
| new SimpleEdge{ From = "D", To = "D", Cost = 10 }, | |
| new SimpleEdge{ From = "D", To = "E", Cost = 01 }, | |
| new SimpleEdge{ From = "E", To = "B", Cost = 10 }, | |
| new SimpleEdge{ From = "E", To = "C", Cost = 10 }, | |
| new SimpleEdge{ From = "E", To = "D", Cost = 10 }, | |
| new SimpleEdge{ From = "E", To = "E", Cost = 10 }, | |
| }; | |
| return (nodes, edges); | |
| } | |
| } | |
| public class MatrixItem | |
| { | |
| public MatrixItem() { /* empty */ } | |
| public MatrixItem(string from, string to, double? cost) | |
| { | |
| From = from; | |
| To = to; | |
| Cost = cost; | |
| AddPath(string.Empty); | |
| } | |
| public string From { get; } | |
| public string To { get; } | |
| public double? Cost { get; set; } | |
| public string Path { get; private set; } = ""; | |
| public void AddPath(params string[] path) | |
| { | |
| var list = new List<String>(Path.Split(";").Concat(path).Where(x => x != From & x != To)); | |
| list.Insert(0, From); | |
| list.Add(To); | |
| Path = string.Join(";", list.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct()); | |
| } | |
| public override string ToString() => string.Join(";", Path.Split(";")); | |
| } | |
| public class SimpleEdge | |
| { | |
| public string From { get; set; } | |
| public string To { get; set; } | |
| public double Cost { get; set; } | |
| public override string ToString() => $"{From} -> {To} {Cost:C4}"; | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample output.
