Skip to content

Commit

Permalink
feat: Chu--Liu/Edmonds
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Apr 13, 2024
1 parent f7cfca4 commit 12ecd98
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 3 deletions.
9 changes: 6 additions & 3 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -489,15 +489,18 @@ notebook:
- dfs: 邻接表 DFS
code_ext: hpp
test_ext: cpp
- dijkstra: 单源最短路(Dijkstra)
code_ext: hpp
test_ext: cpp
- kruskal: 最小生成树(Kruskal)
code_ext: hpp
test_ext: cpp
- kruskal_re_tree: Kruskal 重构树
code_ext: hpp
test_ext: cpp
- cle: 最小树形图(Chu--Liu--Edmonds)
code_ext: hpp
test_ext: cpp
- dijkstra: 单源最短路(Dijkstra)
code_ext: hpp
test_ext: cpp
- bm: 单源最短路(Bellman--Ford)
code_ext: hpp
test_ext: cpp
Expand Down
83 changes: 83 additions & 0 deletions src/code/graph/cle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#ifndef TIFALIBS_GRAPH_CLE
#define TIFALIBS_GRAPH_CLE

#include "../ds/dsu_basic.hpp"
#include "../ds/skew_heap.hpp"

namespace tifa_libs::graph {

// edge: {w, u, v}
template <class T>
constexpr vec<std::tuple<T, u32, u32>> cle(u32 n, u32 root, vec<std::tuple<T, u32, u32>> const &arcs) {
ds::SkewHeap<T> heap;
ds::dsu_basic<> uf(n);
vec<u32> used(n, -1_u32), from(n), come(n, -1_u32);
vec<T> from_cost(n);

used[root] = root;
vec<u32> par_e(arcs.size(), -1_u32), stem(n, -1_u32), idxs;

for (u32 i = 0; i < arcs.size(); ++i) {
auto [w, u, v] = arcs[i];
come[v] = heap.push(come[v], w, i);
}

T costs = 0;
for (u32 start = 0; start < n; start++) {
if (~used[start]) continue;
u32 now = start;
vec<u32> chi_e;
u32 cycle = 0;
while (!~used[now] || used[now] == start) {
used[now] = start;
auto &node = heap.d[come[now]];
if (!~come[now]) return {};
u32 src = (u32)uf.find(std::get<1>(arcs[node.idx]));
T cost = heap.weight(come[now]);
u32 idx = node.idx;
come[now] = heap.pop(come[now]);
if (src == now) continue;

from[now] = src, from_cost[now] = cost;
if (!~stem[now]) stem[now] = idx;
costs += cost;
idxs.push_back(idx);
while (cycle) {
par_e[chi_e.back()] = idx;
chi_e.pop_back();
--cycle;
}
chi_e.push_back(idx);

if (used[src] == start) {
u32 p = now;
do {
if (~come[p]) heap.apply(come[p], -from_cost[p]);
if (p != now) {
uf.merge(p, now);
u32 newheap = heap.merge(come[now], come[p]);
come[now = (u32)uf.find(now)] = newheap;
}
p = (u32)uf.find(from[p]);
++cycle;
} while (p != now);
} else now = src;
}
}

vec<u32> used_e(arcs.size());
vec<std::tuple<T, u32, u32>> res;
for (u32 _ = (u32)idxs.size(); _--;) {
u32 idx = idxs[_];
if (used_e[idx]) continue;
auto [w, u, v] = arcs[idx];
res.push_back(arcs[idx]);
u32 x = stem[v];
while (x != idx) used_e[x] = true, x = par_e[x];
}
return res;
}

} // namespace tifa_libs::graph

#endif
4 changes: 4 additions & 0 deletions src/doc_md/graph/cle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: cle
documentation_of: //src/code/graph/cle.hpp
---
3 changes: 3 additions & 0 deletions src/doc_tex/graph/cle.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
最小树形图 (minimum cost arborescence) 即为有向图版本的最小生成树

From \url{https://nyaannyaan.github.io/library/graph/minimum-cost-arborescence.hpp}
17 changes: 17 additions & 0 deletions src/test_cpverifier/aizu/grl_2_b.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/2/GRL_2_B"

#include "../../code/graph/cle.hpp"

int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
u32 n, m, r;
std::cin >> n >> m >> r;
vec<std::tuple<u64, u32, u32>> arcs(m);
for (auto& [w, u, v] : arcs) std::cin >> u >> v >> w;
auto res = tifa_libs::graph::cle(n, r, arcs);
u64 ans = 0;
for (auto [w, u, v] : res) ans += w;
std::cout << ans << '\n';
return 0;
}
23 changes: 23 additions & 0 deletions src/test_cpverifier/library-checker/directedmst.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#define PROBLEM "https://judge.yosupo.jp/problem/directedmst/"

Check failure on line 1 in src/test_cpverifier/library-checker/directedmst.test.cpp

View workflow job for this annotation

GitHub Actions / verify (01)

Failed to test src/test_cpverifier/library-checker/directedmst.test.cpp

#include "../../code/graph/cle.hpp"
#include "../../code/io/ios_container.hpp"

int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
u32 n, m, s;
std::cin >> n >> m >> s;
vec<std::tuple<u64, u32, u32>> arcs;
arcs.reserve(m);
for (auto& [w, u, v] : arcs) std::cin >> u >> v >> w;
auto res = tifa_libs::graph::cle(n, s, arcs);

u64 cost = 0;
vec<u32> ans(n, -1_u32);
ans[s] = s;
for (auto [w, u, v] : res) cost += w, ans[v] = u;
std::cout << cost << '\n'
<< ans << '\n';
return 0;
}
Empty file added src/test_tinplate/graph/cle.cpp
Empty file.

0 comments on commit 12ecd98

Please sign in to comment.