HDU 5732 Subway(树哈希)

题意:

$给定N\le 10^5个节点的2棵树,保证2棵树同构$
$输出一种2棵树的节点映射方式$

分析:

$树同构,想一个和节点顺序无关的哈希函数将树表示$
$一种方法:首先找树的中点,然后将中点作为根$
$叶子节点哈希值为1,对于每一颗树,把它的所有子树的哈希 值排序,然后算出新的哈希值作为总体的哈希值$
$有2个中点的树2个中点都试一下。为了保险可以检查下哈希值有没有重的$
$双hash速度跟标程一样。。所以还不如。$
$直接$map<vector<int>, int>$搞都行。。10^5的数据只有2个$
$时间复杂度O(nlogn)$

代码:

//
//  Created by TaoSama on 2016-07-21
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

typedef long long LL;
const LL seed[2] = {999999937, 999999929};
const LL mod[2] = {1000000007, 1000000009}; //1e9+7/+9
struct Hash {
    LL h[2];
    Hash() {}
    Hash(const LL& first) {
        for(int i = 0; i < 2; ++i) h[i] = first;
    }
    Hash operator+(const Hash& rhs) const {
        Hash ret = *this;
        for(int i = 0; i < 2; ++i) {
            ret.h[i] = ret.h[i] * seed[i] % mod[i];
            if((ret.h[i] += rhs.h[i]) >= mod[i]) ret.h[i] -= mod[i];
        }
        return ret;
    }
    bool operator<(const Hash& rhs) const {
        return make_pair(h[0], h[1]) < make_pair(rhs.h[0], rhs.h[1]);
    }
    bool operator==(const Hash& rhs) const {
        return make_pair(h[0], h[1]) == make_pair(rhs.h[0], rhs.h[1]);
    }

    void see() {
        printf("(%llu %llu)\n", h[0], h[1]);
    }
};

int n;
vector<int> G[2][N];

void getDiameter(int u, int f, int d, int idx, pair<int, int>& diameter) {
    diameter = max(diameter, make_pair(d, u));
    vector<int>& cur = G[idx][u];
    for(auto& v : cur) {
        if(v == f) continue;
        getDiameter(v, u, d + 1, idx, diameter);
    }
}

bool getPath(int u, int f, int t, int idx, vector<int>& path) {
    path.push_back(u);
    if(u == t) return true;
    vector<int>& cur = G[idx][u];
    for(auto& v : cur) {
        if(v == f) continue;
        if(getPath(v, u, t, idx, path)) return true;
    }
    path.pop_back();
    return false;
}

vector<pair<Hash, int> > treeHash[2][N];

Hash getHash(int u, int f, int idx) {
    vector<int>& cur = G[idx][u];
    vector<pair<Hash, int> > sons;
    for(auto& v : cur) {
        if(v == f) continue;
        sons.push_back({getHash(v, u, idx), v});
    }

    Hash h(1);
    sort(sons.begin(), sons.end());
    for(auto& v : sons) h = h + v.first;
    treeHash[idx][u].swap(sons);
    return h;
}

map<string, int> mp[2];
vector<string> names[2];
int ID(string s, int idx) {
    if(mp[idx].count(s)) return mp[idx][s];
    names[idx].push_back(s);
    mp[idx][s] = names[idx].size();
    return mp[idx][s];
}

void init(int idx) {
    mp[idx].clear(); names[idx].clear();
    for(int i = 1; i <= n; ++i) G[idx][i].clear();
}

void OLE(string s) {
    while(1)
        puts(s.c_str());
}

void RE() {
    printf("%d\n", *((int*)0));
}

bool match(vector<pair<Hash, int> >& cur, vector<pair<Hash, int> >& nxt,
           vector<pair<int, int> >& ans) {
    if(cur.size() != nxt.size()) return false;
    int cnt = 0;
    for(int i = 0; i < cur.size(); ++i) {
        bool ok = false;
        for(int j = i; j < nxt.size() && cur[i].first == nxt[j].first; ++j) {
            swap(nxt[i], nxt[j]);
            if(match(treeHash[0][cur[i].second], treeHash[1][nxt[i].second], ans)) {
                ++cnt;
                ok = true;
                ans.push_back({cur[i].second, nxt[i].second});
                break;
            }
        }
        if(!ok) {
            while(cnt--) ans.pop_back();
            return false;
        }
    }
    return true;
}

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\1010.in", "r", stdin);
//    freopen("C:\\Users\\TaoSama\\Desktop\\out.txt", "w", stdout);
#endif
    ios_base::sync_with_stdio(0);
    clock_t _ = clock();

    while(scanf("%d", &n) == 1) {
        for(int i = 0; i < 2; ++i) {
            init(i);

            for(int j = 1; j < n; ++j) {
                char a[20], b[20]; scanf("%s%s", a, b);
                int u = ID(a, i), v = ID(b, i);
//                printf("%d->%d\n", u, v);
                G[i][u].push_back(v);
                G[i][v].push_back(u);
            }
//            puts("");
        }

        vector<pair<Hash, int> > hashes[2];
        for(int i = 0; i < 2; ++i) {
            pair<int, int> diameter = { -INF, -INF};
            getDiameter(1, -1, 0, i, diameter);
            int u = diameter.second;
            diameter = { -INF, -INF};
            getDiameter(u, -1, 0, i, diameter);
            int v = diameter.second;

//            printf("diameter %d -> %d\n", u, v);

            vector<int> path;
            getPath(u, -1, v, i, path);
            int sz = path.size();
            int x = path[sz >> 1], y = -1;
            if(~path.size() & 1) y = path[sz / 2 - 1];
            hashes[i].push_back({getHash(x, y, i), x});
            if(~y) hashes[i].push_back({getHash(y, x, i), y});

//            printf("start %d %d\n", x, y);

            sort(hashes[i].begin(), hashes[i].end());
        }

        vector<pair<int, int> > ans;
        if(!match(hashes[0], hashes[1], ans)) RE();

//        prln(ans.size());
        if(ans.size() != n) OLE("WA");

        for(int i = 0; i < ans.size(); ++i) {
            int u, v; tie(u, v) = ans[i];
            printf("%s %s\n", names[0][u - 1].c_str(), names[1][v - 1].c_str());
        }
    }

#ifdef LOCAL
    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
    return 0;
}