NKOJ 3458 (POJ 1635)地铁系统 (树哈希)

P3458地铁系统

问题描述

一些大城市的地铁线路呈一棵树状,一条树枝就是一条双向地铁道路,它直接连接两个站点。任意两个站点间,有且仅有一条路径可以到达。
大多数这样的城市都有一个中央地铁站,你是一个地铁迷,假设你现在就在一座这样的城市,你想要探索所有的地铁站。你从中央地铁站出发,随机选了一条地铁线就出发了。每到一个地铁站,你都会选一条没走过的道路继续乘地铁旅行。如果当前你所在的地铁站连接的所有道路你都探索过了,那么你会回到上一个车站,继续探索,直到你探索玩所有地铁站,也就是每条道路来回走过两次(其实就是深度优先搜索遍历一棵树的过程)。那时,你会身处中央车站,你凭记忆写下了一串由0和1构成的数字,来表示整个旅行的过程,其中0表示你离中央车站远了一点,1表示你离中央车站近了一点(0表示向下搜索,1表示回溯)。
这里写图片描述
如上图所示,中间的大黑圆点表示中央车站,从它出法,遍历整棵树的顺序可以有很多种,右侧给出了其中的3中顺序。它们都表示遍历同一棵树。
你的记事本上记下了两次探索过程,问这两次探索的是否是相同的地铁系统?

输入格式

两行,每行一个由0和1构成的字符串,字符串的长度不超过3000.

输出格式

如果两个字符串表示的是相同的地铁系统,输出“same”,否则输出”different”

样例输入

样例1:
0010011101001011
0100011011001011
样例2:
0100101100100111
0011000111010101

样例输出

样例1:
same
样例2:
different


用栈模拟递归过程来连边,连完边之后直接树哈希。

关于树哈希,这道题我用的是,令父亲节点的哈希值为
Hash[fa]=(apHash[son1])%qpHash[son2]%q......b%q H a s h [ f a ] = ( a ∗ p ⨁ H a s h [ s o n 1 ] ) % q ∗ p ⨁ H a s h [ s o n 2 ] % q . . . . . . ∗ b % q
递归计算即可。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#define N 5005
using namespace std;
const int a=233;
const int p=1223;
const int mod=1000007;
const int b=1926;
int T,S[N],top,tot;
vector<int>to[N];
char s[N];
int Hash(int x)
{
    int i,y,ans=a;
    vector<int>tmp;
    if(!to[x].size())return 1;
    for(i=0;i<to[x].size();i++)tmp.push_back(Hash(to[x][i]));
    sort(tmp.begin(),tmp.end());
    for(i=0;i<tmp.size();i++)ans=(ans*p^tmp[i])%mod;
    return ans*b%mod;
}
int Work()
{
    int i,j,k,l=strlen(s);
    S[top=1]=tot=1;
    to[1].clear();
    for(i=0;i<l;i++)
    {
        if(s[i]=='0')
        {
            to[S[top]].push_back(++tot);
            S[++top]=tot;to[tot].clear();
        }
        else top--;
    }
    return Hash(1);
}
int main()
{
    int x,y;
    scanf("%d",&T);
    while(T--)
    {
        scanf("\n%s",s);x=Work();
        scanf("\n%s",s);y=Work();
        if(x==y)puts("same");
        else puts("different");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值