【哈希】【动态规划】[NOIP模拟赛]仔细的检查

nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上。另一天nodgd更无聊,就又画了一张。
这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点u0在第一幅图中编号为u1,在第二副图中编号为u2。
于是,nodgd决定检查一下他画出的两棵树到底是不是一样的。nodgd已经给每棵树的节点都从1到n进行了编号,即每棵树有n个节点。
如果存在一个1到n的排列p1,p2…pn,对于第一幅图中的任意一条边(i,j),在第二幅图中都能找到一条边(pi,pj),则认为这两幅图中的树是一样的。

题目解析:
把整个数hash一下,然后比较,同时按照size进行排序重新建树,最后dfn值进行匹配输出就好了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
const int MAXN=200005;
const int MAXM=400005;
const int IFN=999999999;
const long long MOD=1000000000000007LL;
const int RAN = 10097;
struct node{int v;node *next;};
pair<long long, int> tmp[MAXN+10];
int n;
struct Tree{
    int dcnt, dep[MAXN+10], Fa[MAXN+10];
    node Edges[MAXM*2 + 10], Edges2[MAXM*2 + 10];
    long long hash_val[MAXN+10];
    int sz[MAXN+10], dfn[MAXN+10];
    node *adj[MAXN+10], *adj2[MAXN+10], *ecnt, *ecnt2;
    Tree(){
        dcnt=0;
        ecnt=Edges;
        ecnt2=Edges2;
    }
    void addedge(int u, int v){
        ++ecnt;
        ecnt->v = v;
        ecnt->next = adj[u];
        adj[u] = ecnt;
    }
    void addedge2(int u, int v){
        ++ecnt2;
        ecnt2->v = v;
        ecnt2->next = adj2[u];
        adj2[u] = ecnt2;
    }
    void dfs1(int u, int fa){
        sz[u] = 1;

        for(node *p=adj[u];p;p=p->next){
            if(p->v != fa){
                dfs1(p->v, u);
                sz[u] += sz[p->v];
            }
        }
        int cnt = 0;
        for(node *p=adj[u];p;p=p->next)
            if(p->v != fa)
                tmp[++cnt] = make_pair(hash_val[p->v], p->v);
        sort(tmp+1, tmp+1+cnt);
        hash_val[u] = (0 ^ sz[u]) % MOD;
        for(int i=1;i<=cnt;i++){
            hash_val[u] = (hash_val[u] * RAN ^ (tmp[i].first)) % MOD;
            addedge2(u, tmp[i].second);
        }
    }
    void dfs2(int u, int fa){
        if(u <= n)
            dfn[++dcnt] = u;
        for(node *p=adj2[u];p;p=p->next)
            if(p->v != fa)
                dfs2(p->v, u);
    }
    int FindMID(){
        int Max = 0, ret = -1;
        queue<pair<int, int> > que;
        que.push(make_pair(1, 0));
        while(!que.empty()){
            pair<int, int> u = que.front(); que.pop();
            for(node *p=adj[u.first];p;p=p->next){
                if(p->v != u.second){
                    dep[p->v] = dep[u.first] + 1;
                    que.push(make_pair(p->v, u.first));
                    if(dep[p->v] > Max){
                        Max = dep[p->v];
                        ret = p->v;
                    }
                }
            }
        }
        que.push(make_pair(ret, 0));
        dep[ret] = 0;
        Max = 0; ret = -1;
        while(!que.empty()){
            pair<int, int> u = que.front(); que.pop();
            for(node *p=adj[u.first];p;p=p->next){
                if(p->v != u.second){
                    dep[p->v] = dep[u.first] + 1;
                    que.push(make_pair(p->v, u.first));
                    if(dep[p->v] > Max){
                        Max = dep[p->v];
                        ret = p->v;
                    }
                    Fa[p->v] = u.first;
                }
            }
        }
        Max /= 2;
        int now = ret;
        while(Max--)
            now = Fa[now];
        return now;
    }
    int Read(){
        int u, v;
        for(int i=1;i<n;i++){
            scanf("%d%d", &u, &v);
            addedge(u, n+i); addedge(n+i, u);
            addedge(v, n+i); addedge(n+i, v);
        }
        int md = FindMID();
        dfs1(md, -1); dfs2(md, -1);
        return hash_val[md];
    }
}Tree1, Tree2;
int con[MAXN+10];
int main(){
    scanf("%d", &n);
    int h1 = Tree1.Read();
    int h2 = Tree2.Read();
    if(h1 != h2) printf("NO\n");
    else{
        printf("YES\n");
        for(int i=1;i<=n;i++)
            con[Tree1.dfn[i]] = Tree2.dfn[i];
        for(int i=1;i<=n;i++)
            printf("%d ", con[i]);
    }

    return 0;
}

posted on 2015-11-04 13:33  JeremyGuo  阅读(173)  评论(0编辑  收藏  举报

导航