二维hash(Uva 12886)
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=88791(题目连接)
这道道题就是让你在大矩阵里找小矩阵,用矩阵hash
用矩阵hash之前我们先定义下面这些玩意
hash1[][]记录横列的的hash值
hash2[][]记录纵向的hahs值
hash表示小矩阵的hash值
定义两个种子常数
const ULL seed1=10000007;
const ULL seed2=100000007;
两个种子的值不能相同,因为有时横向和纵向的hash值会相同。所以要用不同的种子值,orz= =
先求小矩阵的的hash值
1 ULL get_hash() 2 { 3 ULL t=0; 4 for(int i=0;i<x;i++) 5 { 6 ULL cnt=0; 7 for(int j=0;j<y;j++) 8 cnt=cnt*seed1+s[i][j];// 9 t=t*seed2+cnt; 10 } 11 return t; 12 }
然后在大矩阵中构造小矩阵。。。。。想见代码吧= =
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #define maxn 2005 using namespace std; typedef unsigned long long ULL; const ULL seed1=10000007; const ULL seed2=100000007; char s[maxn][maxn]; char ch[maxn][maxn]; ULL hash1[maxn][maxn]; ULL hash2[maxn][maxn]; ULL hash; ULL ans; int x,y,n,m; ULL get_hash() { ULL t=0; for(int i=0;i<x;i++) { ULL cnt=0; for(int j=0;j<y;j++) cnt=cnt*seed1+s[i][j]; t=t*seed2+cnt; } return t; } void count_num() { ULL c=1; for(int i=0;i<y;i++) c=c*seed1; //等会求构造矩阵的hash值需要减去第j-y位置的字符的hash值,所以要进行这步。。。 for(int i=0;i<n;i++) { ULL cnt=0; for(int j=0;j<y;j++) cnt=cnt*seed1+ch[i][j]; hash1[i][y-1]=cnt; for(int j=y;j<m;j++) { hash1[i][j]=hash1[i][j-1]*seed1-ch[i][j-y]*c+ch[i][j];//求横列的hash值 } } c=1; for(int i=0;i<x;i++) c=c*seed2; for(int i=y-1;i<m;i++) { ULL a=0; for(int j=0;j<x;j++) a=a*seed2+hash1[j][i];//这里因为将横列的的字符用他的hash值代替= = hash2[x-1][i]=a; if(a==hash) ans++; for(int j=x;j<n;j++) { hash2[j][i]=hash2[j-1][i]*seed2-hash1[j-x][i]*c+hash1[j][i]; if(hash2[j][i]==hash)//相同ans++ ans++; } } } int main() { while(scanf("%d %d %d %d",&x,&y,&n,&m)!=EOF) { getchar(); memset(hash1,0,sizeof(hash1)); memset(hash2,0,sizeof(hash2)); for(int i=0;i<x;i++) scanf("%s",s[i]); for(int i=0;i<n;i++) scanf("%s",ch[i]); hash=get_hash(); ans=0; count_num(); printf("%llu\n",ans); } return 0; }