您的位置:首页 > 大数据 > 人工智能

UVALive - 6893 The Big Painting (BKDRhash扩展到二维矩阵)

2017-08-14 20:46 477 查看
传送门:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4905

题意大意:

给出一个模式字符矩阵,然后再给出一个匹配字符矩阵,问模式字符矩阵在匹配字符矩阵中出现的次数。可以看样例,那更加直观。

题解:

既然是字符匹配,那么首先想到是关于字符处理的一些知识,比如KMP,AC自动机,后缀树组等等。但是这些都不会!!!!至于KMP没应用到过二维的。前段时间学习了BKDRhash字符串哈希。当时练习的是求解一维匹配的。现在要将它转化到二维。其实思路很简单。如果读者还不了解BKDRhash,那就先了解一下BKDRhash。然后将每一列或者每一行对其hash,这里用的对每一列。把一列当成一维字符串进行哈希。如下图:



如上图假设匹配的是红色区域内的字符矩阵,那么对于第一列来讲(将每一列看成一维的字符串哈希处理)它的哈希值就是col1='a'*seed^2+'b'*seed^1+'c'*seed^0,(seed是其系数基值)第二列就是col2='d'*seed^2+'e'*seed^1+'f'*seed^0,第三列col3='g'*seed^2+'h'*seed^1+'k'*seed^0;那么现在应该把这个矩阵合并成一个哈希值。现在把这个字符矩阵平铺开得:‘a
’ ‘b ’ ‘c ’ ‘d ’ ‘e ’ ‘f ’ ‘g ’ ‘h ’ ‘k’,如果把它看成一维的话的哈希值是多少呢:'a'*seed^8+'b'*seed^7+'c'*seed^6+'d'*seed^5+'e'*seed^4+'f'*seed^3+'g'*seed^2+'h'*seed^1+'k'*seed^0;那么看看这个哈希值怎么由col1,col2,col3得来呢。很容易看出是col1*seed^6+col2*seed^3+col3*seed^0,也就是现在的基值是base[3]即base[row],row是模式串的行。剩下的就看看代码吧。注意行列在处理的时候有些变化。因为是按着列来哈希的,但输入是一行一行输入的。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int MAXN = 2000+100;
typedef unsigned long long LL;
int n1,m1,n2,m2;
LL base[MAXN*MAXN+100];
const int seed = 31;
char s1[MAXN][MAXN],s2[MAXN][MAXN];
LL val,H[MAXN][MAXN];
void init()
{
base[0]=1;
for(int i=1;i<=MAXN*MAXN;i++)
base[i]=base[i-1]*seed;
}
void get_H()
{
val=0;
for(int i=1;i<=n1;i++)
for(int j=1;j<=m1;j++)
val=val*seed+s1[i][j]-'a'+1;

memset(H,0,sizeof(H));
for(int i=1;i<=n2;i++)
{
for(int j=1;j<=m2;j++)
{
H[i][j]=H[i][j-1]*seed+(s2[i][j]-'a'+1);
}
}
}
void work()
{

int ans=0;
for(int i=1;i<=m2-m1+1;i++)
{
int li=i-1,ri=i+m1-1;
LL temp=0;
int j;
for(j=1;j<=n1;j++)
temp=temp*base[m1]+H[j][ri]-H[j][li]*base[m1];
do
{
if(val==temp)
{
//cout<<li<<" "<<ri<<" "<<j<<endl;
ans++;
}
temp-=(H[j-n1][ri]-H[j-n1][li]*base[m1])*base[(n1-1)*m1];
temp=temp*base[m1]+H[j][ri]-H[j][li]*base[m1];
j++;
}while(j<=n2+1);
}
printf("%d\n",ans);
}
int main()
{
init();
while(scanf("%d%d%d%d",&n1,&m1,&n2,&m2)==4&&n1)
{
for(int i=1;i<=n1;i++)
scanf("%s",s1[i]+1);
for(int i=1;i<=n2;i++)
scanf("%s",s2[i]+1);
get_H();
work();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: