Skip to content

Commit a66940d

Browse files
committed
refactor: [graphs] Use tests.h
1 parent b2b1eb7 commit a66940d

File tree

7 files changed

+565
-953
lines changed

7 files changed

+565
-953
lines changed

cpp/graphs/bellman-ford.cpp

Lines changed: 56 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -8,160 +8,85 @@
88
* https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
99
*/
1010

11-
#include <bits/stdc++.h>
11+
#include "tests.h"
12+
#include "graphs.h"
1213

13-
using namespace std;
14-
15-
/* ===========================================================================
16-
* Data structures
17-
* ===========================================================================
18-
*/
19-
// Edge is a pair of nodes with weight [u, v, w]
20-
using Edge = array<int, 3>;
21-
22-
// Graph is a pair of V nodes & array of E edges
23-
using Graph = pair<int, vector<Edge>>;
24-
25-
/* ===========================================================================
26-
* Test helpers
27-
* ===========================================================================
28-
*/
29-
class _00_test
30-
{
31-
public:
32-
_00_test(const string &name) : name(name) {}
33-
34-
string getName(void) const { return name; }
35-
36-
virtual vector<int> shortestPaths(const Graph &g, int src = 0) = 0;
37-
38-
private:
39-
string name;
40-
};
14+
using namespace Graphs;
4115

4216
/* ===========================================================================
4317
* Algorithms implementation
4418
* ===========================================================================
4519
*/
20+
#define _bf_desc "Bellman-Ford - Single source shortest path to all nodes"
4621

4722
/* TC : Best O(E), Average O(V*E), Worst O(V*E) => O(n^3) when E = V^2
4823
* For a complete graph E = V(V-1)/2 => O(E) = O(V^2).
4924
* SC : O(V) => O(n)
5025
*/
51-
class _01_bellman_ford : public _00_test
26+
vi_t shortestPaths(int nodes, const vi2_t &edges, int source)
5227
{
53-
public:
54-
_01_bellman_ford()
55-
: _00_test("Bellman-Ford single source shortest path to all "
56-
"nodes")
57-
{
28+
int ne = size(edges);
29+
vi_t d(nodes, X);
30+
d[source] = 0;
31+
fii (i, (nodes - 1)) {
32+
fii (j, ne) {
33+
int u = edges[j][0];
34+
int v = edges[j][1];
35+
int w = edges[j][2];
36+
if (d[u] != X) d[v] = min(d[v], d[u] + w);
37+
}
5838
}
59-
60-
vector<int> shortestPaths(const Graph &g, int src = 0) override
61-
{
62-
const int n = g.first;
63-
vector<int> d(n, INT_MAX);
64-
d[src] = 0;
65-
for (int i = 0; i < n - 1; i++)
66-
for (auto [u, v, w] : g.second)
67-
if (d[u] != INT_MAX)
68-
d[v] = min(d[v], d[u] + w);
69-
// Detect negative cycle
70-
for (auto [u, v, w] : g.second)
71-
if (d[u] != INT_MAX && d[v] > d[u] + w)
72-
return {INT_MIN};
73-
return d;
39+
// Detect negative cycle
40+
fii (j, ne) {
41+
int u = edges[j][0];
42+
int v = edges[j][1];
43+
int w = edges[j][2];
44+
if (d[u] != X && d[v] > d[u] + w) return {NX};
7445
}
75-
};
46+
return d;
47+
}
7648

7749
/* ===========================================================================
7850
* Test code
7951
* ===========================================================================
8052
*/
81-
template <class Container = vector<int>>
82-
string _vec2str(const Container &vec)
83-
{
84-
ostringstream oss;
85-
using T = Container::value_type;
86-
oss << "{";
87-
copy(vec.begin(), vec.end() - 1, ostream_iterator<T>(oss, ", "));
88-
oss << vec.back();
89-
oss << "}";
90-
return oss.str();
91-
}
92-
93-
string _g2str(const Graph &g)
53+
#define _bf_check(n, ed, s, e) \
54+
vi_t a = shortestPaths(n, ed, s); \
55+
string _pre("distances"), im, am; \
56+
im += to_string(n, ed); \
57+
im += format(", source = {}", s); \
58+
am = format("{} = {}", _pre, to_string(a)); \
59+
CHECK_EQ(e, a); \
60+
SHOW_OUTPUT(im, am);
61+
62+
TEST(shortestPaths, _bf_desc)
9463
{
95-
ostringstream oss;
96-
oss << "{";
97-
for (int i = 0; auto e : g.second) {
98-
if (i++) oss << ", ";
99-
oss << _vec2str<Edge>(e);
100-
}
101-
oss << "}";
102-
return oss.str();
103-
}
104-
105-
void test_impl(const vector<pair<Graph, int>> &ip,
106-
const vector<vector<int>> &op, shared_ptr<_00_test> f)
107-
{
108-
for (size_t i = 0; i < ip.size(); i++) {
109-
vector<int> t = f->shortestPaths(ip[i].first, ip[i].second);
110-
if (t != op[i]) {
111-
cerr << f->getName() << " test failed: "
112-
<< "expected " << _vec2str(op[i]) << ", actual "
113-
<< _vec2str(t) << "." << endl;
114-
exit(1);
115-
}
116-
117-
if (getenv("SHOW_TEST_OUTPUT"))
118-
cout << " test-" << i << ": "
119-
<< "input: graph = " << _g2str(ip[i].first)
120-
<< ", source = " << ip[i].second
121-
<< " output: nums = " << _vec2str(t) << "\n";
122-
}
123-
}
124-
125-
int main(int, char **)
126-
{
127-
Graph g1{4, {{2, 1, -10}, {3, 2, 3}, {0, 3, 5}, {0, 1, 4}}};
128-
Graph g2{5,
129-
{{0, 1, -1},
130-
{0, 2, 3},
131-
{1, 2, 3},
132-
{1, 3, 2},
133-
{1, 4, 2},
134-
{3, 2, 5},
135-
{3, 1, 1},
136-
{4, 3, -3}}};
137-
Graph ng1(g1);
138-
ng1.second.push_back({1, 3, 5}); // Negative cycle graph
139-
140-
vector<pair<Graph, int>> ip{
141-
{g1, 0},
142-
{g2, 0},
143-
{ng1, 0},
144-
};
145-
146-
vector<vector<int>> op{
64+
vi_t _nodes = {4, 5, 5};
65+
vi_t _sources = {0, 0, 0};
66+
vector<vi2_t> _edges;
67+
_edges.push_back({{2, 1, -10}, {3, 2, 3}, {0, 3, 5}, {0, 1, 4}});
68+
_edges.push_back({{0, 1, -1},
69+
{0, 2, 3},
70+
{1, 2, 3},
71+
{1, 3, 2},
72+
{1, 4, 2},
73+
{3, 2, 5},
74+
{3, 1, 1},
75+
{4, 3, -3}});
76+
vi2_t nge = _edges[0];
77+
nge.push_back({1, 3, 5}); // Negative cycle edge in graph
78+
_edges.push_back(nge);
79+
80+
vi2_t _distances = {
14781
{0, -2, 8, 5},
14882
{0, -1, 2, -2, 1},
149-
{INT_MIN}, // Indicate negative cycle is detected in graph
83+
{NX}, // When graph has negative cycle
15084
};
15185

152-
vector<shared_ptr<_00_test>> impls{
153-
make_shared<_01_bellman_ford>(),
154-
};
155-
156-
for (size_t i = 0; i < impls.size(); i++) {
157-
if (getenv("SHOW_TEST_OUTPUT"))
158-
cout << "Testing implementation " << i + 1 << " "
159-
<< impls[i]->getName() << "\n";
160-
161-
test_impl(ip, op, impls[i]);
86+
int n = size(_nodes);
87+
fii (i, n) {
88+
_bf_check(_nodes[i], _edges[i], _sources[i], _distances[i]);
16289
}
163-
164-
cout << "Executed " << impls.size() << " implementations"
165-
<< " with " << ip.size() << " tests." << endl;
166-
return 0;
16790
}
91+
92+
INIT_TEST_MAIN();

0 commit comments

Comments
 (0)