Skip to content

rooted_tree_isomorphism.hpp

SECTIONGraph INCLUDEnoya/rooted_tree_isomorphism.hpp

Assign canonical hash labels to rooted subtrees for isomorphism testing.

Verified by rooted_tree_isomorphism_classification.

给有根树分配同构类型编号;用于判断多棵根树是否只差孩子排列,或压缩相同子树结构。

Implementation

View on GitHub

#ifndef NOYA_ROOTED_TREE_ISOMORPHISM_HPP
#define NOYA_ROOTED_TREE_ISOMORPHISM_HPP 1

/// @complexity Time: O(n log n) from sorting child labels.
/// Space: O(n).

#include <algorithm>
#include <map>
#include <vector>

namespace noya {

/// @brief Assign canonical hash labels to rooted subtrees for isomorphism testing.
struct tree_isomorphism {
  std::map<std::vector<int>, int> mp;
  int cnt = 0;

  /// @brief Compute canonical labels for all nodes of a rooted tree.
  /// @return Vector mapping each node to its canonical subtree label.
  std::vector<int> solve(const std::vector<std::vector<int>> &g,
                         const int root = 0) {
    int N = int(g.size());
    std::vector<int> ans(N);
    auto dfs = [&](auto &self, int u, int parent) -> int {
      std::vector<int> sons;
      for (int v : g[u]) {
        if (v != parent) {
          sons.push_back(self(self, v, u));
        }
      }
      std::sort(sons.begin(), sons.end());
      if (!mp.count(sons))
        mp[sons] = cnt++;
      return ans[u] = mp[sons];
    };
    dfs(dfs, root, -1);
    return ans;
  }
};

} // namespace noya

#endif // NOYA_ROOTED_TREE_ISOMORPHISM_HPP
#include <algorithm>
#include <map>
#include <vector>

/// @complexity Time: O(n log n) from sorting child labels.
/// Space: O(n).

namespace noya {

/// @brief Assign canonical hash labels to rooted subtrees for isomorphism testing.
struct tree_isomorphism {
  std::map<std::vector<int>, int> mp;
  int cnt = 0;

  /// @brief Compute canonical labels for all nodes of a rooted tree.
  /// @return Vector mapping each node to its canonical subtree label.
  std::vector<int> solve(const std::vector<std::vector<int>> &g,
                         const int root = 0) {
    int N = int(g.size());
    std::vector<int> ans(N);
    auto dfs = [&](auto &self, int u, int parent) -> int {
      std::vector<int> sons;
      for (int v : g[u]) {
        if (v != parent) {
          sons.push_back(self(self, v, u));
        }
      }
      std::sort(sons.begin(), sons.end());
      if (!mp.count(sons))
        mp[sons] = cnt++;
      return ans[u] = mp[sons];
    };
    dfs(dfs, root, -1);
    return ans;
  }
};

} // namespace noya