1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#pragma once

#include <cassert><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <vector><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <utility>

#include "internal/dev_env.hpp"
#include "structure/graph.hpp"

namespace uni {


// Thanks to: https://qiita.com/drken/items/4b4c3f1824339b090202
template<class Graph = graph<>>
struct centroid_decomposition {
    using size_type = internal::size_t;

    std::vector<size_type> centroids;

  private:
    const Graph& graph;
    std::vector<size_type> _size, _parent;
    std::vector<bool> _used;

  public:
    centroid_decomposition(const Graph& _graph) noexcept(NO_EXCEPT)
      : graph(_graph),
        _size(graph.vertices()), _parent(graph.vertices()), _used(graph.vertices())
    {}

    inline const auto& sizes() const noexcept(NO_EXCEPT) { return this->_size; }
    inline const auto& parents() const noexcept(NO_EXCEPT) { return this->_parent; }
    inline const auto& used() const noexcept(NO_EXCEPT) { return this->_used; }

    inline size_type size(const size_type v) const noexcept(NO_EXCEPT) {
        assert(0 <= v && v < this->graph.vertices());<--- Unsigned positive
        return this->_size[v];
    }
    inline size_type parent(const size_type v) const noexcept(NO_EXCEPT) {
        assert(0 <= v && v < this->graph.vertices());<--- Unsigned positive
        return this->_parent[v];
    }
    inline bool used(const size_type v) const noexcept(NO_EXCEPT) {
        assert(0 <= v && v < this->graph.vertices());<--- Unsigned positive
        return this->_used[v];
    }

    const std::vector<size_type>& find(const size_type v, const size_type sz, const size_type p = -1) noexcept(NO_EXCEPT) {
        assert(not this->_used[v]);

        this->_size[v] = 1, this->_parent[v] = p;
        bool found = true;
        ITR(e, this->graph[v]) {
            if(e.to == p) continue;
            if(this->_used[e.to]) continue;

            this->find(e.to, sz, v);
            if(this->_size[e.to] > sz / 2) found = false;
            this->_size[v] += this->_size[e.to];
        }
        if(sz - this->_size[v] > sz / 2) found = false;
        if(found) this->centroids.push_back(v);

        return this->centroids;
    }

    auto decompose(const size_type root, const size_type sz) noexcept(NO_EXCEPT) {
    assert(not this->_used[root]);

        std::vector<std::pair<size_type,size_type>> subtrees;

        this->centroids.clear();
        this->find(root, sz);

        const size_type centroid = this->centroids[0];
        this->_used[centroid] = true;

        ITR(e, this->graph[centroid]) {
            if(this->_used[e.to]) continue;
            if(e.to == this->_parent[centroid]) {
                subtrees.emplace_back(e.to, sz - this->_size[centroid]);
            }
            else {
                subtrees.emplace_back(e.to, this->_size[e.to]);
            }
        }

        return std::make_pair(centroid, subtrees);
    }

    auto decompose(const size_type root = 0) noexcept(NO_EXCEPT) {
        return this->decompose(root, this->graph.vertices());
    }
};


} // namespace uni