changeset 23:c3fb5f666e2d

graphs: Two graph algorithms
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 09 Apr 2023 17:17:04 +0200
parents 68cf11026c57
children b89680a8af68
files graph.cc
diffstat 1 files changed, 83 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/graph.cc	Sun Apr 09 12:07:14 2023 +0200
+++ b/graph.cc	Sun Apr 09 17:17:04 2023 +0200
@@ -2,6 +2,7 @@
 
 #include <iterator>
 #include <ranges>
+#include <tuple>
 #include <vector>
 
 using namespace std;
@@ -10,10 +11,11 @@
     requires random_access_iterator<Iter> && is_same_v<remove_cv_t<iter_value_t<Iter>>, remove_cv_t<T>>
 class MDSpan {
     const Iter begin, end;
-    const size_t Nx, Ny;
 
     public:
 
+    const size_t Nx, Ny;
+
     template<typename R>
         requires is_same_v<ranges::iterator_t<R>, Iter>
     MDSpan(R&& rng, size_t Nx, size_t Ny) : begin(std::begin(rng)), end(std::end(rng)), Nx(Nx), Ny(Ny) {
@@ -32,6 +34,15 @@
         size_t ix = y * Nx + x;
         return begin[ix];
     }
+
+    void print() {
+        for (size_t y = 0; y < Ny; y++) {
+            for (size_t x = 0; x < Nx; x++) {
+                fmt::print("{:5} ", (*this)[x, y]);
+            }
+            fmt::print("\n");
+        }
+    }
 };
 
 template<typename Cont> requires ranges::range<Cont>
@@ -57,18 +68,82 @@
 
 // https://www.techiedelight.com/single-source-shortest-paths-bellman-ford-algorithm/
 void bellman_ford() {
-    const vector<int> v(42);
+    const size_t nodes = 5;
+    const int inf = numeric_limits<int>::max();
+    vector<int> v(nodes * nodes);
 
     //MDSpan<const int, vector<int>::const_iterator> mds = make_mdspan(v, 6, 7);
-    auto mds = make_const_mdspan(v, 6, 7);
+    auto adj = make_mdspan(v, nodes, nodes);
+
+    adj[0, 1] = -1;
+    adj[0, 2] = 4;
+    adj[1, 2] = 3;
+    adj[1, 3] = 2;
+    adj[3, 1] = 1;
+    adj[1, 4] = 2;
+    adj[4, 3] = -3;
+    adj[3, 2] = 5;
+
+    adj.print();
+    vector<int> cost(nodes, inf);
+    cost[0] = 0;
+
+    for (int i = 0; i < nodes-1; i++) {
+        for (size_t a = 0; a < nodes; a++) {
+            for (size_t b = 0; b < nodes; b++) {
+                // Not elegant. Need separate store for adjacency, basically.
+                if (a == b || adj[a, b] == 0) continue;
+
+                if (cost[a] + adj[a,b] < cost[b]) cost[b] = cost[a] + adj[a, b];
+            }
+        }
+    }
+
+    fmt::print("{}\n", cost);
+}
 
-    //mds[3, 3] = 47;
-    fmt::print("{}\n", mds[2,3]);
-    //fmt::print("{}\n", mds[3,3]);
+void floyd_warshall() {
+    const size_t nodes = 4;
+    const int inf = numeric_limits<int>::max();
+    vector<tuple<int, int, int>> edges{
+        {1, 0, 4},
+        {1, 2, 3},
+        {3, 1, -1},
+        {0, 2, -2},
+        {2, 3, 2},
+    };
+
+    vector<int> adj_v(nodes*nodes);
+    auto adj = make_mdspan(adj_v, nodes, nodes);
+
+    for (const auto& e : edges){
+        adj[get<0>(e), get<1>(e)] = get<2>(e);
+    }
+    for (size_t i = 0; i < nodes; i++) {
+        for (size_t j = 0; j < nodes; j++) {
+            if (i == j) adj[i,j] = 0;
+            else if (adj[i,j] == 0) adj[i,j] = inf;
+        }
+    }
+
+    adj.print();
+
+    for (size_t j = 0; j < nodes; j++) {
+        for (size_t i = 0; i < nodes; i++) {
+            for (size_t k = 0; k < nodes; k++) {
+                if (adj[i, j] != inf && adj[j, k] != inf) {
+                    if (adj[i,j] + adj[j,k] < adj[i,k]) adj[i,k] = adj[i,j]+adj[j,k];
+                }
+            }
+        }
+    }
+
+    fmt::print("\n");
+    adj.print();
 }
 
 int main(void) {
-    bellman_ford();
-
+    timeit_f([]() { bellman_ford(); }, "bellman-ford");
+    floyd_warshall();
     return 0;
 }