Hash在信息学竞赛中的一类应用 中的某道例题
"不难想到的算法是使用两个字符串分别表示两棵树,但是如果使用Hash的话应该怎么做呢?
可以使用一种类似树状递推的方法来计算Hash值:
对于一个节点v,先求出它所有儿子节点的Hash值,并从小到大排序,记作H1,H2,„,HD。那么v的Hash值就可以计算为:
(((a * p) ^ H1 mod q) * p ^ H2 mod q).....
换句话说,就是从某个常数开始,每次乘以p,和一个元素异或,再除以q取余,再乘以p,和下一个元素异或,除以q取余„„一直进行到最后一个元素为止。最后把所得到的结果乘以b,再对q取余。"
#include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <queue> #include <deque> #include <bitset> #include <list> #include <cstdlib> #include <climits> #include <cmath> #include <ctime> #include <algorithm> #include <stack> #include <sstream> #include <numeric> #include <fstream> #include <functional> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef unsigned long long ULL; typedef vector<int> VI; typedef pair<int,int> pii; const int INF = INT_MAX / 3; const double eps = 1e-8; const LL LINF = 1e17; const double DINF = 1e60; const int maxn = 3005; const int C = 12345, p = 67890, q = 1e9 + 7; char str1[maxn], str2[maxn]; VI ch[maxn], hash[maxn]; int fa[maxn]; int dfs(int now) { int m = ch[now].size(); if(m == 0) return C; for(int i = 0;i < m;i++) { hash[now].PB(dfs(ch[now][i])); } sort(hash[now].begin(),hash[now].end()); int ret = C; for(int i = 0;i < m;i++) { ret = (ret * p) ^ hash[now][i] % q; } return ret; } int gethash(char *str) { memset(fa,0,sizeof(fa)); int len = strlen(str), u = 0, sz = 1; for(int i = 0;i < len;i++) { ch[i].clear(); hash[i].clear(); } for(int i = 0;i < len;i++) { if(str[i] == '0') { ch[u].PB(sz); fa[sz] = u; u = sz++; } else { u = fa[u]; } } return dfs(0); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%s%s",str1,str2); if(gethash(str1) == gethash(str2)) { puts("same"); } else puts("different"); } return 0; }