Skip to content

Instantly share code, notes, and snippets.

@JerryNixon
Created January 21, 2021 00:00
Show Gist options
  • Select an option

  • Save JerryNixon/df68ec2053ef5af8da69855c030cf95e to your computer and use it in GitHub Desktop.

Select an option

Save JerryNixon/df68ec2053ef5af8da69855c030cf95e to your computer and use it in GitHub Desktop.
Simple implementation of Floyd-Warshall in C#
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}";
}
}
@JerryNixon

Copy link
Copy Markdown
Author

Sample output.
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment