Task: Floyd-Warshall algorithm


C++: #include <iostream>
#include <vector>
#include <sstream>

void print(std::vector<std::vector<double>> dist, std::vector<std::vector<int>> next) {
  std::cout << "(pair, dist, path)" << std::endl;
  const auto size = std::size(next);
  for (auto i = 0; i < size; ++i) {
    for (auto j = 0; j < size; ++j) {
      if (i != j) {
        auto u = i + 1;
        auto v = j + 1;
        std::cout << "(" << u << " -> " << v << ", " << dist[i][j]
          << ", ";
        std::stringstream path;
        path << u;
        do {
          u = next[u - 1][v - 1];
          path << " -> " << u;
        } while (u != v);
        std::cout << path.str() << ")" << std::endl;
      }
    }
  }
}

void solve(std::vector<std::vector<int>> w_s, const int num_vertices) {
  std::vector<std::vector<double>> dist(num_vertices);
  for (auto& dim : dist) {
    for (auto i = 0; i < num_vertices; ++i) {
      dim.push_back(INT_MAX);
    }
  }
  for (auto& w : w_s) {
    dist[w[0] - 1][w[1] - 1] = w[2];
  }
  std::vector<std::vector<int>> next(num_vertices);
  for (auto i = 0; i < num_vertices; ++i) {
    for (auto j = 0; j < num_vertices; ++j) {
      next[i].push_back(0);
    }
    for (auto j = 0; j < num_vertices; ++j) {
      if (i != j) {
        next[i][j] = j + 1;
      }
    }
  }
  for (auto k = 0; k < num_vertices; ++k) {
    for (auto i = 0; i < num_vertices; ++i) {
      for (auto j = 0; j < num_vertices; ++j) {
        if (dist[i][j] > dist[i][k] + dist[k][j]) {
          dist[i][j] = dist[i][k] + dist[k][j];
          next[i][j] = next[i][k];
        }
      }
    }
  }
  print(dist, next);
}

int main() {
  std::vector<std::vector<int>> w = {
    { 1, 3, -2 },
    { 2, 1, 4 },
    { 2, 3, 3 },
    { 3, 4, 2 },
    { 4, 2, -1 },
  };
  int num_vertices = 4;
  solve(w, num_vertices);
  std::cin.ignore();
  std::cin.get();
  return 0;
}









Fortran: module floyd_warshall_algorithm

  use, intrinsic :: ieee_arithmetic

  implicit none

  integer, parameter :: floating_point_kind = &
       & ieee_selected_real_kind (6, 37)
  integer, parameter :: fpk = floating_point_kind

  integer, parameter :: nil_vertex = 0

  type :: edge
     integer :: u
     real(kind = fpk) :: weight
     integer :: v
  end type edge

  type :: edge_list
     type(edge), allocatable :: element(:)
  end type edge_list

contains

  subroutine make_example_graph (edges)
    type(edge_list), intent(out) :: edges

    allocate (edges%element(1:5))
    edges%element(1) = edge (1, -2.0, 3)
    edges%element(2) = edge (3, +2.0, 4)
    edges%element(3) = edge (4, -1.0, 2)
    edges%element(4) = edge (2, +4.0, 1)
    edges%element(5) = edge (2, +3.0, 3)
  end subroutine make_example_graph

  function find_max_vertex (edges) result (n)
    type(edge_list), intent(in) :: edges
    integer n

    integer i

    n = 1
    do i = lbound (edges%element, 1), ubound (edges%element, 1)
       n = max (n, edges%element(i)%u)
       n = max (n, edges%element(i)%v)
    end do
  end function find_max_vertex

  subroutine floyd_warshall (edges, max_vertex, distance, next_vertex)

    type(edge_list), intent(in) :: edges
    integer, intent(out) :: max_vertex
    real(kind = fpk), allocatable, intent(out) :: distance(:,:)
    integer, allocatable, intent(out) :: next_vertex(:,:)

    integer :: n
    integer :: i, j, k
    integer :: u, v
    real(kind = fpk) :: dist_ikj
    real(kind = fpk) :: infinity

    n = find_max_vertex (edges)
    max_vertex = n

    allocate (distance(1:n, 1:n))
    allocate (next_vertex(1:n, 1:n))

    infinity = ieee_value (1.0_fpk,  ieee_positive_inf)

    

    do i = 1, n
       do j = 1, n
          distance(i, j) = infinity
          next_vertex (i, j) = nil_vertex
       end do
    end do
    do i = lbound (edges%element, 1), ubound (edges%element, 1)
       u = edges%element(i)%u
       v = edges%element(i)%v
       distance(u, v) = edges%element(i)%weight
       next_vertex(u, v) = v
    end do
    do i = 1, n
       distance(i, i) = 0.0_fpk 
       next_vertex(i, i) = i
    end do

    

    do k = 1, n
       do i = 1, n
          do j = 1, n
             dist_ikj = distance(i, k) + distance(k, j)
             if (dist_ikj < distance(i, j)) then
                distance(i, j) = dist_ikj
                next_vertex(i, j) = next_vertex(i, k)
             end if
          end do
       end do
    end do

  end subroutine floyd_warshall

  subroutine print_path (next_vertex, u, v)
    integer, intent(in) :: next_vertex(:,:)
    integer, intent(in) :: u, v

    integer i

    if (next_vertex(u, v) /= nil_vertex) then
       i = u
       write (*, '(I0)', advance = 'no') i
       do while (i /= v)
          i = next_vertex(i, v)
          write (*, '('' -> '', I0)', advance = 'no') i
       end do
    end if
  end subroutine print_path

end module floyd_warshall_algorithm

program floyd_warshall_task

  use, non_intrinsic :: floyd_warshall_algorithm

  implicit none

  type(edge_list) :: example_graph
  integer :: max_vertex
  real(kind = fpk), allocatable :: distance(:,:)
  integer, allocatable :: next_vertex(:,:)
  integer :: u, v

  call make_example_graph (example_graph)
  call floyd_warshall (example_graph, max_vertex, distance, &
       &               next_vertex)

1000 format (1X, I0, ' -> ', I0, 5X, F4.1, 6X)

  write (*, '(''  pair     distance    path'')')
  write (*, '(''---------------------------------------'')')
  do u = 1, max_vertex
     do v = 1, max_vertex
        if (u /= v) then
           write (*, 1000, advance = 'no') u, v, distance(u, v)
           call print_path (next_vertex, u, v)
           write (*, '()', advance = 'yes')
        end if
     end do
  end do

end program floyd_warshall_task