树的同构 poj 1635

博客介绍了POJ 1635问题,即判断两棵有根树是否同构。同构的本质是通过哈希来实现,通过计算每个节点子树的权值和来确定树的结构。如果任何节点的权值组合不同,都将导致树结构的不相同。博客中提供了问题解析和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

http://poj.org/problem?id=1635

题意


判断两个有根树是否同构。


解析


判断两个有根树是否同构,本质上是hash应用,每个点的权值是这个子树的权值和。树上某一组合不同都会导致最终结构的不同。


代码

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
using namespace std;
const int maxn = 3000+10;
typedef long long LL;
vector<int>G1[maxn];
vector<int>G2[maxn];
int p1[maxn], p2[maxn];
struct hash{
    int length;
    LL value;
    hash():length(0), value(0){}
    hash(char c):length(1), value(c){}
    hash(int l, LL v):length(l), value(v){}
    bool operator < (const hash &a) const
    {
        return value<a.value;
    }
};
const LL magic = 321;
LL pow(LL a, int b){
    LL res = 1;
    while (b) {
        if (b & 1) 
            res *= a;
        a *= a;
        b>>=1;
    }
    return res;
}

hash operator + (const hash &a, const hash &b)
{
    return hash(a.length+b.length, a.value*pow(magic, b.length)+b.value);
}

void operator += (hash &a, const hash &b){
    a = a+b;
}

vector<hash>child[maxn];
hash dfs(int pre, int cur, vector<int>G[maxn]) {
    hash ret;
    child[cur].clear();
    for (int i=0; i<G[cur].size(); i++) {
        if (G[cur][i] == pre)
            continue;
        child[cur].push_back(dfs(cur, G[cur][i], G));
    }
    sort(child[cur].begin(), child[cur].end());
    for (int i=0; i<child[cur].size(); i++) 
        ret += child[cur][i];
    ret = '(' + ret + ')';
    return ret;
}

LL gethash(int root, vector<int>m[maxn]) {
    return dfs(-1, root, m).value;
}
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        char s[maxn];
        scanf("%s", s);
        int slen = strlen(s);
        int t=0;
        int now = 0;
    for (int i=0; i<slen; i++)
        G1[i].clear(), G2[i].clear();

        for (int i=0; i<slen; i++) {
            if (s[i] == '1')
                now = p1[now];
            else
            {
                t++;
                G1[now].push_back(t);
                p1[t] = now;
                now = t;
            }
        }
        char p[maxn];
        scanf("%s", p);
        int plen = strlen(p);
        t = 0;
        now = 0;
        for (int i=0; i<plen; i++) {
            if (p[i] == '1') 
                now = p2[now];
            else {
                t++;
                G2[now].push_back(t);
                p2[t] = now;
                now = t;
            }
        }
    if (slen != plen) {
        puts("differrent");
            continue;
    }
        LL tree1 = gethash(0, G1);
        LL tree2 = gethash(0, G2);
        if (tree1 == tree2)
            puts("same");
        else
            puts("different");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值