Skip to content

Commit 91457d6

Browse files
committed
Add graph shortest path
1 parent 32f6d99 commit 91457d6

File tree

4 files changed

+135
-27
lines changed

4 files changed

+135
-27
lines changed

cp-algo/data_structures/stack_union.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
namespace cp_algo::data_structures {
66
template<class datatype>
77
struct stack_union {
8-
stack_union(int n = 0): n(n), head(n), next(1), data(1) {}
8+
stack_union(int n = 0): head(n), next(1), data(1) {}
99

1010
void push(int v, datatype const& vdata) {
1111
next.push_back(head[v]);
12-
head[v] = size(next) - 1;
12+
head[v] = std::size(next) - 1;
1313
data.push_back(vdata);
1414
}
1515
template<typename... Args>
@@ -19,7 +19,9 @@ namespace cp_algo::data_structures {
1919
data.emplace_back(std::forward<Args...>(vdata...));
2020
}
2121

22-
int n;
22+
size_t size() const {return std::size(head);}
23+
size_t nodes() const {return std::size(data);}
24+
2325
std::vector<int> head, next;
2426
std::vector<datatype> data;
2527
};

cp-algo/graph/base.hpp

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55
#include <ranges>
66
#include <vector>
77
namespace cp_algo::graph {
8+
using node_index = int;
9+
using edge_index = int;
810
struct edge_base {
9-
int to;
11+
node_index to;
1012

1113
edge_base() {}
12-
edge_base(int v): to(v) {}
14+
edge_base(node_index v): to(v) {}
1315

14-
static auto read(int v0 = 0) {
15-
int u, v;
16+
static auto read(node_index v0 = 0) {
17+
node_index u, v;
1618
std::cin >> u >> v;
1719
return std::pair{u - v0, edge_base(v - v0)};
1820
}
@@ -21,54 +23,74 @@ namespace cp_algo::graph {
2123
return {from};
2224
}
2325
};
24-
template<typename edge_info>
25-
concept edge_type = std::is_base_of_v<edge_base, edge_info>;
26+
27+
struct weighted_edge: edge_base {
28+
int64_t w;
29+
30+
weighted_edge() {}
31+
weighted_edge(node_index v, int64_t w): edge_base(v), w(w) {}
32+
33+
static auto read(node_index v0 = 0) {
34+
node_index u, v;
35+
int64_t w;
36+
std::cin >> u >> v >> w;
37+
return std::pair{u - v0, weighted_edge{v - v0, w}};
38+
}
39+
40+
weighted_edge backedge(node_index from) const {
41+
return {from, w};
42+
}
43+
};
44+
45+
template<typename edge>
46+
concept edge_type = std::is_base_of_v<edge_base, edge>;
47+
template<typename edge>
48+
concept weighted_edge_type = std::is_base_of_v<weighted_edge, edge>;
2649

2750
enum type {directed = 0, undirected = 1};
28-
template<type _undirected, edge_type edge_info = edge_base>
51+
template<type _undirected, edge_type edge_t = edge_base>
2952
struct graph {
3053
static constexpr bool undirected = _undirected;
31-
graph(int n, int v0 = 0): _n(n), _m(0), v0(v0), _adj(n) {}
54+
graph(int n, int v0 = 0): v0(v0), _adj(n) {}
3255

33-
void add_edge(int u, edge_info e) {
34-
_m++;
56+
void add_edge(node_index u, edge_t e) {
3557
_adj.push(u, size(edges));
3658
edges.push_back(e);
3759
if constexpr (undirected) {
3860
_adj.push(e.to, size(edges));
3961
}
4062
edges.push_back(e.backedge(u));
4163
}
42-
void read_edges(int m) {
43-
for(int i = 0; i < m; i++) {
44-
auto [u, e] = edge_info::read(v0);
64+
void read_edges(node_index m) {
65+
for(edge_index i = 0; i < m; i++) {
66+
auto [u, e] = edge_t::read(v0);
4567
add_edge(u, e);
4668
}
4769
}
48-
void call_adjacent(int v, auto &&callback, auto &&terminate) const {
70+
void call_adjacent(node_index v, auto &&callback, auto &&terminate) const {
4971
for(int sv = _adj.head[v]; sv && !terminate(); sv = _adj.next[sv]) {
5072
callback(_adj.data[sv]);
5173
}
5274
}
53-
void call_adjacent(int v, auto &&callback) const {
75+
void call_adjacent(node_index v, auto &&callback) const {
5476
call_adjacent(v, callback, [](){return false;});
5577
}
5678
void call_edges(auto &&callback) const {
57-
for(int v: nodes_view()) {
58-
call_adjacent(v, [&](int e) {callback(v, e);});
79+
for(node_index v: nodes_view()) {
80+
call_adjacent(v, [&](edge_index e) {callback(v, e);});
5981
}
6082
}
6183
auto nodes_view() const {
62-
return std::views::iota(0, _n);
84+
return std::views::iota(0, n());
6385
}
6486
auto const& incidence_lists() const {return _adj;}
65-
auto const& edge(int e) const {return edges[e];}
66-
int n() const {return _n;}
67-
int m() const {return _m;}
87+
edge_t const& edge(edge_index e) const {return edges[e];}
88+
size_t n() const {return _adj.size();}
89+
size_t m() const {return size(edges) / 2;}
6890
private:
69-
int _n, _m, v0;
70-
std::vector<edge_info> edges;
71-
data_structures::stack_union<int> _adj;
91+
node_index v0;
92+
std::vector<edge_t> edges;
93+
data_structures::stack_union<edge_index> _adj;
7294
};
7395
}
7496
#endif // CP_ALGO_GRAPH_BASE_HPP

cp-algo/graph/shortest_path.hpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef CP_ALGO_GRAPH_SHORTEST_PATH_HPP
2+
#define CP_ALGO_GRAPH_SHORTEST_PATH_HPP
3+
#include "base.hpp"
4+
#include <algorithm>
5+
#include <queue>
6+
namespace cp_algo::graph {
7+
template<type _, weighted_edge_type edge_t>
8+
auto dijkstra(graph<_, edge_t> const& g, int s) {
9+
static constexpr uint64_t inf = 1e18;
10+
std::vector<uint64_t> dist(g.n(), inf);
11+
std::vector<std::pair<node_index, edge_index>> pre(g.n());
12+
using que_t = std::pair<uint64_t, node_index>;
13+
std::priority_queue<que_t, std::vector<que_t>, std::greater<>> que;
14+
dist[s] = 0;
15+
que.push({0, s});
16+
while(!empty(que)) {
17+
auto [dv, v] = que.top();
18+
que.pop();
19+
if(dv != dist[v]) {
20+
continue;
21+
}
22+
g.call_adjacent(v, [&](auto e) {
23+
node_index u = g.edge(e).to;
24+
auto w = g.edge(e).w;
25+
if(dist[v] + w < dist[u]) {
26+
pre[u] = {v, e};
27+
dist[u] = dist[v] + w;
28+
que.push({dist[u], u});
29+
}
30+
});
31+
}
32+
return std::pair{dist, pre};
33+
}
34+
35+
template<type _, weighted_edge_type edge_t>
36+
auto shortest_path(graph<_, edge_t> const& g, int s, int t) {
37+
static constexpr uint64_t inf = 1e18;
38+
auto [dist, pre] = dijkstra(g, s);
39+
std::vector<std::pair<node_index, edge_index>> path;
40+
int64_t d = dist[t] == inf ? -1 : dist[t];
41+
while(d != -1 && t != s) {
42+
path.push_back(pre[t]);
43+
t = pre[t].first;
44+
}
45+
std::ranges::reverse(path);
46+
return std::pair{d, path};
47+
}
48+
}
49+
#endif // CP_ALGO_GRAPH_SHORTEST_PATH_HPP

verify/graph/shortest_path.test.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @brief Shortest Path
2+
#define PROBLEM "https://judge.yosupo.jp/problem/shortest_path"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include "cp-algo/graph/shortest_path.hpp"
5+
#include <bits/stdc++.h>
6+
7+
using namespace std;
8+
using namespace cp_algo::graph;
9+
10+
void solve() {
11+
int n, m, s, t;
12+
cin >> n >> m >> s >> t;
13+
graph<directed, weighted_edge> g(n);
14+
g.read_edges(m);
15+
auto [X, Y] = shortest_path(g, s, t);
16+
if(X == -1) {
17+
cout << X << "\n";
18+
} else {
19+
cout << X << ' ' << size(Y) << "\n";
20+
for(auto [u, e]: Y) {
21+
cout << u << ' ' << g.edge(e).to << "\n";
22+
}
23+
}
24+
}
25+
26+
signed main() {
27+
//freopen("input.txt", "r", stdin);
28+
ios::sync_with_stdio(0);
29+
cin.tie(0);
30+
int t = 1;
31+
//cin >> t;
32+
while(t--) {
33+
solve();
34+
}
35+
}

0 commit comments

Comments
 (0)