Graph Algorithms
Single Source Shortest Paths
Bellman-Ford Algorithm
- detect negative loop
- relax edges for 
- see all vertexes in each loop
 
- based on triangle inequality

test1.txt
7 10 1 7
1 2 2
1 3 5
2 3 4
2 4 6
2 5 10
3 4 2
4 6 1
5 6 3
5 7 5
6 7 9
16
C++
#include <fstream>
#include <stdio.h>
#include <vector>
#define MAX_N 10'000
#define MAX_K 10'000
#define INF 1'000'000'000
using namespace std;
struct Edge {
  int u, v, weight;
};
int N, K, S, G;
int dist[MAX_N], path[MAX_N];
Edge E[MAX_K];
void init(int s) {
  for (int i = 0; i < N; ++i) {
    dist[i] = INF;
    path[i] = -1;
  }
  dist[s] = 0;
}
void relax(int u, int v, int weight) {
  if (dist[v] > dist[u] + weight) {
    dist[v] = dist[u] + weight;
    path[v] = u;
  }
}
bool bellman_ford() {
  for (int i = 0; i < N - 1; ++i) {
    for (auto e : E) {
      relax(e.u, e.v, e.weight);
    }
  }
  for (auto e : E) {
    if (dist[e.v] > dist[e.u] + e.weight) {
      return false;
    }
  }
  return true;
}
void print_path(int s, int v) {
  if (s == v) {
    printf("%d", s + 1);
  } else if (v < 0) {
    printf("\n No path");
  } else {
    print_path(s, path[v]);
    printf("->%d", v + 1);
  }
}
int main() {
  ifstream ifs("../testset/single_source_shortest_path/test1.txt");
  ifs >> N >> K >> S >> G;
  --S;
  --G;
  for (int i = 0; i < K * 2; i += 2) {
    int u, v, weight;
    ifs >> u >> v >> weight;
    --u;
    --v;
    E[i] = Edge{u, v, weight};
    E[i + 1] = Edge{v, u, weight};
  }
  init(S);
  if (bellman_ford()) {
    printf("dist=%d\n", dist[G]);
    printf("path=");
    print_path(S, G);
    printf("\n");
  } else {
    printf("detect negative loop\n");
  }
}
// dist=16
// path=1->3->4->6->5->7
Python
INF = float('inf')
def ns(f):
    return next(f).strip()
class Edge:
    def __init__(self, u, v, weight):
        self.u = u
        self.v = v
        self.weight = weight
with open("../testset/single_source_shortest_path/test1.txt", 'r') as f:
    N, K, S, T = map(int, ns(f).split())
    S -= 1
    T -= 1
    E = []
    for _ in range(K):
        u, v, weight = map(int, ns(f).split())
        u -= 1
        v -= 1
        E.append(Edge(u, v, weight))
        E.append(Edge(v, u, weight))
dist = [INF] * N
dist[S] = 0
path = [-1] * N
def relax(u, v, weight):
    global dist, path
    if dist[v] > dist[u] + weight:
        dist[v] = dist[u] + weight
        path[v] = u
def bellman_ford():
    # return True if the graph has negative loops.
    for _ in range(N - 1):
        for e in E:
            relax(e.u, e.v, e.weight)
    for e in E:
        if dist[e.v] < dist[e.u] + e.weight:
            return False
    return True
def _print_path(s, v):
    if s == v:
        print(s + 1, end='')
    elif v < 0:
        print('\nNo path', end='')
    else:
        _print_path(s, path[v])
        print(f"->{v + 1}", end='')
def print_path(s, v):
    _print_path(s, v)
    print()
bellman_ford()
print(f"shortest distance={dist[T]}")
print("shortest path=", end='')
print_path(S, T)
# shortest distance=16
# shortest path=1->3->4->6->5->7
Dijkstra's Algorithm
- -> (used heap queue)
- use priority queue
- see only the most nearest vertex
 
C++
#include <fstream>
#include <queue>
#include <stdio.h>
#include <vector>
#define MAX_N 10'000
#define MAX_K 10'000
#define INF 1'000'000'000
using namespace std;
typedef pair<int, int> P;
struct Edge {
  int u, v, weight;
  Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {}
};
int N, K, S, T;
vector<Edge> G[MAX_N];
int dist[MAX_N], path[MAX_N];
void init(int s) {
  fill(dist, dist + N, INF);
  fill(path, path + N, -1);
  dist[s] = 0;
}
void dijkstra(int s) {
  init(s);
  priority_queue<P, vector<P>, greater<P>> q;
  q.push(P(0, s));
  while (!q.empty()) {
    P p = q.top();
    q.pop();
    int u = p.second;
    if (dist[u] < p.first) {
      continue;
    }
    for (auto e : G[u]) {
      if (dist[e.v] > dist[u] + e.weight) {
        // relax
        dist[e.v] = dist[u] + e.weight;
        path[e.v] = u;
        q.push(P(dist[e.v], e.v));
      }
    }
  }
}
void _print_path(int s, int v) {
  if (s == v) {
    printf("%d", s + 1);
  } else if (v < 0) {
    printf("No path\n");
  } else {
    _print_path(s, path[v]);
    printf("->%d", v + 1);
  }
}
void print_path(int s, int v) {
  _print_path(s, v);
  printf("\n");
}
int main() {
  ifstream ifs("../testset/single_source_shortest_path/test1.txt");
  ifs >> N >> K >> S >> T;
  --S;
  --T;
  for (int i = 0; i < K; ++i) {
    int u, v, weight;
    ifs >> u >> v >> weight;
    --u;
    --v;
    G[u].emplace_back(u, v, weight);
    G[v].emplace_back(v, u, weight);
  }
  dijkstra(S);
  printf("shortest distance=%d\n", dist[T]);
  printf("shortest path=");
  print_path(S, T);
}
// shortest distance=16
// shortest path=1->3->4->6->5->7
Python
from heapq import heapify, heappop, heappush
INF = float('inf')
def ns(f):
    return next(f).strip()
class Edge:
    def __init__(self, u, v, weight):
        self.u = u
        self.v = v
        self.weight = weight
with open("../testset/single_source_shortest_path/test1.txt", 'r') as f:
    N, K, S, T = map(int, ns(f).split())
    S -= 1
    T -= 1
    G = [[] for _ in range(N)]
    for _ in range(K):
        u, v, weight = map(int, ns(f).split())
        u -= 1
        v -= 1
        G[u].append(Edge(u, v, weight))
        G[v].append(Edge(v, u, weight))
dist = [INF] * N
dist[S] = 0
path = [-1] * N
def dijkstra():
    global dist, path
    q = [[0, S]]
    heapify(q)
    while len(q) > 0:
        p = heappop(q)
        u = p[1]
        if dist[u] < p[0]:
            continue
        for e in G[u]:
            if dist[e.v] > dist[u] + e.weight:
                dist[e.v] = dist[u] + e.weight
                path[e.v] = u
                heappush(q, [dist[e.v], e.v])
def _print_path(s, v):
    if s == v:
        print(s + 1, end='')
    elif v < 0:
        print('\nNo path', end='')
    else:
        _print_path(s, path[v])
        print(f"->{v + 1}", end='')
def print_path(s, v):
    _print_path(s, v)
    print()
dijkstra()
print(f"shortest distance={dist[T]}")
print("shortest path=", end='')
print_path(S, T)
# shortest distance=16
# shortest path=1->3->4->6->5->7
All Pairs Shortest Paths
Warshall-Floyd Algorithm
- use DP to consider a path from  to  is through  or not
- which more shorter is path through or not
 

test1.txt
5 9
1 2 3
1 3 8
1 5 -4
2 4 1
2 5 7
3 2 4
4 1 2
4 3 -5
5 4 6
0 1 -3 2 -4
3 0 -4 1 -1
7 4 0 5 3
2 -1 -5 0 -2
8 5 1 6 0
C++
#include <algorithm>
#include <fstream>
#include <iostream>
#include <stdio.h>
#define MAX_N 1'000
#define INF 1'000'000'000
using namespace std;
int N, K;
int d[MAX_N][MAX_N];
void warshall_floyd() {
  for (int k = 0; k < N; ++k) {
    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < N; ++j) {
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
      }
    }
  }
}
int main() {
  ifstream ifs("../testset/all_pairs_shortest_path/test1.txt");
  ifs >> N >> K;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      if (i == j) {
        d[i][j] = 0;
      } else {
        d[i][j] = INF;
      }
    }
  }
  for (int i = 0; i < K; ++i) {
    int u, v, weight;
    ifs >> u >> v >> weight;
    --u;
    --v;
    d[u][v] = weight;
    // if non-direction graph add d[v][u]
    // d[v][u] = weight;
  }
  warshall_floyd();
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      printf("%d ", d[i][j]);
    }
    printf("\n");
  }
}
Python
INF = float('inf')
def ns(f):
    return next(f).strip()
with open("../testset/all_pairs_shortest_path/test1.txt", 'r') as f:
    N, K = map(int, ns(f).split())
    d = [[0 if i == j else INF for j in range(N)] for i in range(N)]
    for _ in range(K):
        u, v, weight = map(int, ns(f).split())
        u -= 1
        v -= 1
        d[u][v] = weight
        # if non-direction graph add d[v][u]
        # d[v][u] = weight
def warshall_floyd():
    global d
    for k in range(N):
        for i in range(N):
            for j in range(N):
                d[i][j] = min(d[i][j], d[i][k] + d[k][j])
warshall_floyd()
for _d in d:
    print(' '.join(map(str, _d)))
MST: Minimum Spanning Tree
Kruscal's Algorithm
- be similar to Bellman-Ford Algorithm
- use Union-Find Tree
- add vertexes of the min weight edge into tree repeatedly if the tree doesn't include the vertexes

test1.txt
7 9
1 3 1
2 3 2
2 5 10
3 4 3
3 6 7
4 6 1
4 7 5
5 6 5
6 7 8
17
C++
#include <algorithm>
#include <fstream>
#include <memory.h>
#include <stdio.h>
#define MAX_N 10'000
#define MAX_K 10'000
using namespace std;
struct Edge {
  int u, v, weight;
};
int N, K, ans;
int par[MAX_N], rnk[MAX_N]{};
Edge E[MAX_K];
void init() {
  for (int i = 0; i < N; ++i) {
    par[i] = i;
  }
}
int find(int u) {
  if (par[u] == u) {
    return u;
  }
  return par[u] = find(par[u]);
}
void unite(int u, int v) {
  u = find(u);
  v = find(v);
  if (u == v) {
    return;
  }
  if (rnk[u] < rnk[v]) {
    par[u] = v;
  } else {
    par[v] = u;
    if (rnk[u] == rnk[v]) {
      ++rnk[u];
    }
  }
}
bool same(int u, int v) { return find(u) == find(v); }
int kruscal() {
  int res = 0;
  sort(E, E + K, [](const Edge &e1, const Edge &e2) { return e1.weight < e2.weight; });
  init();
  for (auto e : E) {
    if (!same(e.u, e.v)) {
      res += e.weight;
      unite(e.u, e.v);
    }
  }
  return res;
}
int main() {
  ifstream ifs("../testset/minimum_spanning_tree/test1.txt");
  ifs >> N >> K;
  for (int i = 0; i < K; ++i) {
    int u, v, weight;
    ifs >> u >> v >> weight;
    E[i] = Edge{--u, --v, weight};
  }
  ans = kruscal();
  printf("%d\n", ans);
}
Python
def ns(f):
    return next(f).strip()
class Edge:
    def __init__(self, u, v, weight):
        self.u = u
        self.v = v
        self.weight = weight
with open("../testset/minimum_spanning_tree/test1.txt", 'r') as f:
    N, K = map(int, ns(f).split())
    E = []
    for _ in range(K):
        u, v, weight = map(int, ns(f).split())
        E.append(Edge(u - 1, v - 1, weight))
par = [i for i in range(N)]
rnk = [0] * N
def find(u):
    global par
    if par[u] == u:
        return u
    par[u] = find(par[u])
    return par[u]
def unite(u, v):
    global par, rnk
    u = find(u)
    v = find(v)
    if u == v:
        return
    if rnk[u] < rnk[v]:
        par[u] = v
    else:
        par[v] = u
        if rnk[u] == rnk[v]:
            rnk[u] += 1
def same(u, v):
    return find(u) == find(v)
def kruscal():
    res = 0
    E.sort(key=lambda x: x.weight)
    for e in E:
        if not same(e.u, e.v):
            res += e.weight
            unite(e.u, e.v)
    return res
ans = kruscal()
print(ans)
Prim's Algorithm
- be similar to Dijkstra's Algorithm
- use priority queue ->
- add vertex having the shortest distance from added vertexes in the tree into tree repeatedly
C++
#include <fstream>
#include <queue>
#include <stdio.h>
#include <utility>
#include <vector>
#define MAX_N 10'000
#define MAX_K 10'000
using namespace std;
typedef pair<int, int> P;
struct Edge {
  int u, v, weight;
  Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {}
};
int N, K, ans;
vector<Edge> G[MAX_N];
bool used[MAX_N]{};
int prim() {
  int res = 0;
  used[0] = true;
  priority_queue<P, vector<P>, greater<P>> q;
  for (auto e : G[0]) {
    q.push(P(e.weight, e.v));
  }
  while (!q.empty()) {
    P p = q.top();
    q.pop();
    int u = p.second;
    if (used[u]) {
      continue;
    }
    used[u] = true;
    res += p.first;
    for (auto e : G[u]) {
      if (!used[e.v]) {
        q.push(P(e.weight, e.v));
      }
    }
  }
  return res;
}
int main() {
  ifstream ifs("../testset/minimum_spanning_tree/test1.txt");
  ifs >> N >> K;
  for (int i = 0; i < K; ++i) {
    int u, v, weight;
    ifs >> u >> v >> weight;
    --u;
    --v;
    G[u].emplace_back(u, v, weight);
    G[v].emplace_back(v, u, weight);
  }
  ans = prim();
  printf("%d\n", ans);
}
Python
from heapq import heapify, heappop, heappush
def ns(f):
    return next(f).strip()
class Edge:
    def __init__(self, u, v, weight):
        self.u = u
        self.v = v
        self.weight = weight
with open("../testset/minimum_spanning_tree/test1.txt", 'r') as f:
    N, K = map(int, ns(f).split())
    G = [[] for _ in range(N)]
    for _ in range(K):
        u, v, weight = map(int, ns(f).split())
        u -= 1
        v -= 1
        G[u].append(Edge(u, v, weight))
        G[v].append(Edge(v, u, weight))
used = [False] * N
def prim():
    global used
    res = 0
    used[0] = True
    q = [[e.weight, e.v] for e in G[0]]
    heapify(q)
    while len(q) > 0:
        p = heappop(q)
        u = p[1]
        if used[u]:
            continue
        used[u] = True
        res += p[0]
        for e in G[u]:
            if not used[e.v]:
                heappush(q, [e.weight, e.v])
    return res
ans = prim()
print(ans)