Skip to content

Commit cd7931d

Browse files
committed
bellman ford algo
1 parent a414dfa commit cd7931d

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

algo/bellman_ford/bellman_ford.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
/// bellman ford algorithm
5+
/// given directed edges with real value weights and a source node
6+
/// return cost an path from source node to every other node
7+
/// or find the nodes in a negative cycle
8+
/// works when nodes disconnected from source exists
9+
10+
/// in:
11+
/// [number of nodes] [number of edges]
12+
/// [source node]
13+
/// (for each edge) [from node] [to node] [integer cost]
14+
15+
/**
16+
in:
17+
5 3
18+
1
19+
1 2 10
20+
1 3 20
21+
4 5 30
22+
23+
out:
24+
1, cost: 0, path: 1
25+
2, cost: 10, path: 1 2
26+
3, cost: 20, path: 1 3
27+
4 unreachable
28+
5 unreachable
29+
30+
in:
31+
5 6
32+
1
33+
1 2 1
34+
2 3 10
35+
3 1 10
36+
2 4 1
37+
4 5 0
38+
5 3 0
39+
40+
out:
41+
1, cost: 0, path: 1
42+
2, cost: 1, path: 1 2
43+
3, cost: 2, path: 1 2 4 5 3
44+
4, cost: 2, path: 1 2 4
45+
5, cost: 2, path: 1 2 4 5
46+
47+
in:
48+
5 5
49+
1
50+
1 2 10
51+
2 3 10
52+
2 4 -1
53+
4 5 -1
54+
5 2 -1
55+
56+
out:
57+
cycle detected
58+
2 4 5
59+
60+
g++ -std=c++20 bellman_ford.cpp -o k
61+
*/
62+
int main () {
63+
int n_nodes, n_edges, i_source;
64+
std::cin >> n_nodes >> n_edges >> i_source;
65+
i_source--;
66+
67+
// initialize distances to infinity except source node
68+
std::vector<int> distances(n_nodes, std::numeric_limits<int>::max());
69+
distances[i_source] = 0;
70+
71+
// initialize predecessor
72+
std::vector<int> predecessors(n_nodes, -1);
73+
74+
// initialize adjacency matrix with costs to edges
75+
// adj[from] = {to, cost}
76+
std::vector<std::vector<std::pair<int,int>>> adj(n_nodes);
77+
int i_from, i_to, cost;
78+
for (int j = 0; j < n_edges; j++) {
79+
std::cin >> i_from >> i_to >> cost;
80+
i_from--; i_to--;
81+
adj[i_from].push_back(std::make_pair(i_to, cost));
82+
}
83+
84+
// compute distances and predecessors
85+
int new_cost;
86+
for (int k = 0; k < n_nodes - 1; k++) {
87+
// iterate through each edge
88+
for (int i_from = 0; i_from < n_nodes; i_from++) {
89+
for (auto [i_to, cost] : adj[i_from]) {
90+
91+
if (distances[i_from] < std::numeric_limits<int>::max()) {
92+
new_cost = distances[i_from] + cost;
93+
} else {
94+
new_cost = std::numeric_limits<int>::max();
95+
}
96+
97+
if(new_cost < distances[i_to]) {
98+
// reassign distance and predessor because we found a shorter route
99+
distances[i_to] = new_cost;
100+
predecessors[i_to] = i_from;
101+
}
102+
}
103+
}
104+
}
105+
106+
// detect negative cycles
107+
bool has_cycle = false;
108+
int i_cycle_candidate;
109+
for (int i_from = 0; i_from < n_nodes; i_from++) {
110+
for (auto [i_to, cost] : adj[i_from]) {
111+
112+
if (distances[i_from] < std::numeric_limits<int>::max()) {
113+
new_cost = distances[i_from] + cost;
114+
} else {
115+
new_cost = std::numeric_limits<int>::max();
116+
}
117+
118+
if(new_cost < distances[i_to]) {
119+
// cycle is detected, get candidates for cycle
120+
has_cycle = true;
121+
i_cycle_candidate = i_to;
122+
}
123+
}
124+
}
125+
126+
if (has_cycle) {
127+
// find a node in cycle
128+
std::vector<bool> visited(n_nodes, false);
129+
visited[i_cycle_candidate] = true;
130+
int j = predecessors[i_cycle_candidate];
131+
while (!visited[j]) {
132+
visited[j] = true;
133+
j = predecessors[j];
134+
}
135+
136+
// find nodes in cycle
137+
int i_in_cycle = j;
138+
std::vector<int> cycle = {i_in_cycle};
139+
cycle.reserve(n_nodes);
140+
j = predecessors[i_in_cycle];
141+
while (j != i_in_cycle) {
142+
cycle.push_back(j);
143+
j = predecessors[j];
144+
}
145+
146+
// print cycle
147+
std::cout << "cycle detected\n";
148+
for (int i : cycle | std::views::reverse) {
149+
std::cout << i+1 << " ";
150+
}
151+
std::cout << std::endl;
152+
} else {
153+
// print cost and path to each node from source
154+
std::vector<int> path;
155+
path.reserve(n_nodes);
156+
for (int i = 0; i < n_nodes; i++) {
157+
if (distances[i] < std::numeric_limits<int>::max()) {
158+
// path from i_source to i exists with finite distance
159+
std::cout << i+1 << ", cost: " << distances[i];
160+
161+
// get the path from i_source to i
162+
path = {i};
163+
int j = i;
164+
while (j != i_source) {
165+
j = predecessors[j];
166+
path.push_back(j);
167+
};
168+
169+
// print out the path from i_source to i
170+
std::cout << ", path: ";
171+
for (int j : path | std::views::reverse) {
172+
std::cout << j+1 << " ";
173+
}
174+
std::cout << std::endl;
175+
} else {
176+
// no path from i_source to i
177+
std::cout << i+1 << " unreachable\n";
178+
}
179+
}
180+
}
181+
182+
return 0;
183+
}
184+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
9 11
2+
1
3+
1 2 10
4+
2 3 10
5+
2 4 -1
6+
4 5 -1
7+
5 2 -1
8+
2 6 1
9+
6 7 1
10+
7 2 1
11+
2 8 -1
12+
8 9 -1
13+
9 2 -1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cycle detected
2+
4 5 2

0 commit comments

Comments
 (0)