zoukankan      html  css  js  c++  java
  • 「JSOI2015」isomorphism

    「JSOI2015」isomorphism

    传送门

    我们还是考虑树哈希来判同构。

    但是我们需要使用一些特殊的手段来特殊对待假节点。

    由于是无向树,我们首先求出重心,然后以重心为根跑树哈希。

    此处我们不计算假节点的个数对子树大小的贡献。需要注意的是无向树可能有两个重心。

    树哈希的时候,假节点儿子的哈希值也直接向上贡献(因为假节点有且只有一个儿子)。

    这样我们就可以求出一颗无向树的简化树的哈希值,之后的问题就轻松解决了。

    参考代码:

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #define rg register
    #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
    using namespace std;
    template < class T > inline void read(T& s) {
        s = 0; int f = 0; char c = getchar();
        while ('0' > c || c > '9') f |= c == '-', c = getchar();
        while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
        s = f ? -s : s;
    }
     
    typedef unsigned long long ull;
    const int _ = 1e4 + 5;
    const ull base = 19491001;
     
    int tot, head[_]; struct Edge { int v, nxt; } edge[_ << 1];
    inline void Add_edge(int u, int v) { edge[++tot] = (Edge) { v, head[u] }, head[u] = tot; }
     
    int m, s[_]; vector < ull > H[_];
    int n, real, dgr[_], siz[_], mnx, mx[_]; ull h[_], pow[_], v[_];
     
    inline void dfs1(int u, int f) {
        siz[u] = dgr[u] != 2, mx[u] = 0;
        for (rg int i = head[u]; i; i = edge[i].nxt) {
            int v = edge[i].v; if (v == f) continue ;
            dfs1(v, u), siz[u] += siz[v], mx[u] = max(mx[u], siz[v]);
        }
        mx[u] = max(mx[u], real - siz[u]), mnx = min(mnx, mx[u]);
    }
     
    inline void dfs2(int u, int f) {
        for (rg int i = head[u]; i; i = edge[i].nxt)
            if (edge[i].v != f) dfs2(edge[i].v, u);
        int top = 0;
        for (rg int i = head[u]; i; i = edge[i].nxt)
            if (edge[i].v != f) v[top++] = h[edge[i].v];
        sort(v, v + top), h[u] = top - 1;
        for (rg int i = 0; i < top; ++i) h[u] += pow[i] * v[i];
    }
     
    vector < int > tmp;
    inline bool cmp(const int& i, const int& j) { return s[i] < s[j]; }
     
    inline bool check(int x) {
        for (rg int i = 0; i < tmp.size(); ++i) {
        int y = tmp[i];
        for (rg int j = 0; j < H[x].size(); ++j)
            for (rg int k = 0; k < H[y].size(); ++k)
            if (H[x][j] == H[y][k]) return 0;
        }
        return 1;
    }
     
    int main() {
    #ifndef ONLINE_JUDGE
        file("cpp");
    #endif
        read(m), pow[0] = 1;
        for (rg int i = 1; i < _; ++i) pow[i] = pow[i - 1] * base;    
        for (rg int o = 1; o <= m; ++o) {
            read(n);
            memset(head + 1, tot = 0, sizeof (int) * n);
            memset(dgr + 1, 0, sizeof (int) * n);
            for (rg int u, v, i = 1; i < n; ++i)
                read(u), read(v), Add_edge(u, v), Add_edge(v, u), ++dgr[u], ++dgr[v];
            real = 0;
            for (rg int i = 1; i <= n; ++i) real += dgr[i] != 2;
            mnx = 2e9, dfs1(1, 0);
            s[o] = real, H[o].clear();
            for (rg int i = 1; i <= n; ++i)
                if (mx[i] == mnx) dfs2(i, 0), H[o].push_back(h[i]);
        }
        for (rg int i = 1; i <= m; ++i) if (check(i)) tmp.push_back(i);
        sort(tmp.begin(), tmp.end(), cmp);
        printf("%u
    ", tmp.size());
        for (rg int i = 0; i < tmp.size(); ++i) printf("%d ", s[tmp[i]]);
        return 0;
    }
    
  • 相关阅读:
    阿里云磁盘扩容
    【Vue】WebPack 忽略指定文件或目录
    MySQL 全文索引 (FullText)
    产品设计
    13-Java面向对象-抽象类与接口
    06-数据存储
    07-网络与通信-02-Android中基于HTTP的通信技术
    10-Android 广播接收器 BroadcastReceiver
    09-Android 中 AIDL 的理解与使用
    09-Android 中 AIDL 的理解与使用
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/12364629.html
Copyright © 2011-2022 走看看