Skip to content

rooted_tree_isomorphism.hpp

SECTIONGraph INCLUDEnoya/graph/rooted_tree_isomorphism.hpp

按完整孩子类型签名给根树精确编号,同一分类器跨次复用类型表;共用签名缓冲区、缓存叶子并避免重复查表,不使用概率哈希。

Complexity: Time: \(O(n \log (n + M + 1))\), with \(M\) previously interned types. Space: \(O(n + M + L)\), with \(L\) integers in retained keys; \(O(n)\) recursion depth.

AC 记录:rooted_tree_isomorphism_classification。

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include。

/// @complexity Time: O(n log(n+M+1)), with M previously interned types.
/// Space: O(n+M+L), with L integers in retained keys; O(n) recursion depth.

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

namespace noya {

/// @brief Intern exact rooted-subtree types, shared across calls on this object.
struct tree_isomorphism {
  std::map<std::vector<int>, int> mp;
  int cnt = 0;

  /// @brief Label every subtree rooted at rt, ignoring child order.
  /// Accept an undirected tree or its outward child lists; leave g unchanged.
  /// Compare IDs only within the same type table. Empty input changes nothing.
  std::vector<int> solve(const std::vector<std::vector<int>> &g,
                         const int rt = 0) {
    int N = int(g.size());
    std::vector<int> ans(N);
    if (N == 0) return ans;
    assert(0 <= rt && rt < N);
    // The first postorder vertex is a leaf, so its ID is unchanged.
    auto [leaf, inserted] = mp.try_emplace(std::vector<int>{}, cnt);
    cnt += inserted;
    int leaf_id = leaf->second;
    std::vector<int> ch;
    auto dfs = [&](auto &self, int u, int fa) -> int {
      int children = 0;
      for (int v : g[u]) {
        assert(0 <= v && v < N);
        if (v != fa) {
          self(self, v, u);
          ++children;
        }
      }
      if (children == 0) return ans[u] = leaf_id;
      // Finish children before reusing this scratch; copy only new keys.
      ch.clear();
      ch.reserve(children);
      for (int v : g[u]) if (v != fa) ch.push_back(ans[v]);
      if (!std::is_sorted(ch.begin(), ch.end()))
        std::sort(ch.begin(), ch.end());
      auto size = mp.size();
      auto it = mp.try_emplace(mp.end(), ch, cnt);
      cnt += mp.size() != size;
      return ans[u] = it->second;
    };
    dfs(dfs, rt, -1);
    return ans;
  }
};

} // namespace noya

 // NOYA_ROOTED_TREE_ISOMORPHISM_HPP
#ifndef NOYA_ROOTED_TREE_ISOMORPHISM_HPP
#define NOYA_ROOTED_TREE_ISOMORPHISM_HPP 1

/// @complexity Time: O(n log(n+M+1)), with M previously interned types.
/// Space: O(n+M+L), with L integers in retained keys; O(n) recursion depth.

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

namespace noya {

/// @brief Intern exact rooted-subtree types, shared across calls on this object.
struct tree_isomorphism {
  std::map<std::vector<int>, int> mp;
  int cnt = 0;

  /// @brief Label every subtree rooted at rt, ignoring child order.
  /// Accept an undirected tree or its outward child lists; leave g unchanged.
  /// Compare IDs only within the same type table. Empty input changes nothing.
  std::vector<int> solve(const std::vector<std::vector<int>> &g,
                         const int rt = 0) {
    int N = int(g.size());
    std::vector<int> ans(N);
    if (N == 0) return ans;
    assert(0 <= rt && rt < N);
    // The first postorder vertex is a leaf, so its ID is unchanged.
    auto [leaf, inserted] = mp.try_emplace(std::vector<int>{}, cnt);
    cnt += inserted;
    int leaf_id = leaf->second;
    std::vector<int> ch;
    auto dfs = [&](auto &self, int u, int fa) -> int {
      int children = 0;
      for (int v : g[u]) {
        assert(0 <= v && v < N);
        if (v != fa) {
          self(self, v, u);
          ++children;
        }
      }
      if (children == 0) return ans[u] = leaf_id;
      // Finish children before reusing this scratch; copy only new keys.
      ch.clear();
      ch.reserve(children);
      for (int v : g[u]) if (v != fa) ch.push_back(ans[v]);
      if (!std::is_sorted(ch.begin(), ch.end()))
        std::sort(ch.begin(), ch.end());
      auto size = mp.size();
      auto it = mp.try_emplace(mp.end(), ch, cnt);
      cnt += mp.size() != size;
      return ans[u] = it->second;
    };
    dfs(dfs, rt, -1);
    return ans;
  }
};

} // namespace noya

#endif // NOYA_ROOTED_TREE_ISOMORPHISM_HPP
/// @complexity Time: O(n log(n+M+1)), with M previously interned types.
/// Space: O(n+M+L), with L integers in retained keys; O(n) recursion depth.

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

namespace noya {

/// @brief Intern exact rooted-subtree types, shared across calls on this object.
struct tree_isomorphism {
  std::map<std::vector<int>, int> mp;
  int cnt = 0;

  /// @brief Label every subtree rooted at rt, ignoring child order.
  /// Accept an undirected tree or its outward child lists; leave g unchanged.
  /// Compare IDs only within the same type table. Empty input changes nothing.
  std::vector<int> solve(const std::vector<std::vector<int>> &g,
                         const int rt = 0) {
    int N = int(g.size());
    std::vector<int> ans(N);
    if (N == 0) return ans;
    assert(0 <= rt && rt < N);
    // The first postorder vertex is a leaf, so its ID is unchanged.
    auto [leaf, inserted] = mp.try_emplace(std::vector<int>{}, cnt);
    cnt += inserted;
    int leaf_id = leaf->second;
    std::vector<int> ch;
    auto dfs = [&](auto &self, int u, int fa) -> int {
      int children = 0;
      for (int v : g[u]) {
        assert(0 <= v && v < N);
        if (v != fa) {
          self(self, v, u);
          ++children;
        }
      }
      if (children == 0) return ans[u] = leaf_id;
      // Finish children before reusing this scratch; copy only new keys.
      ch.clear();
      ch.reserve(children);
      for (int v : g[u]) if (v != fa) ch.push_back(ans[v]);
      if (!std::is_sorted(ch.begin(), ch.end()))
        std::sort(ch.begin(), ch.end());
      auto size = mp.size();
      auto it = mp.try_emplace(mp.end(), ch, cnt);
      cnt += mp.size() != size;
      return ans[u] = it->second;
    };
    dfs(dfs, rt, -1);
    return ans;
  }
};

} // namespace noya

 // NOYA_ROOTED_TREE_ISOMORPHISM_HPP