UVA11019题解
题意简述
给出一个
题目分析
此题可以使用字符串哈希。在讲这个题的具体做法之前我们首先来回顾一下一维情况下的字符串哈希是如何做的。字符串哈希是用来快速判断两个字符串是否相同的算法,具体过程如下:
- 首先是一个字符串
(所有字符全部为小写字母,下同),比如abcqwq
。 - 设定一个质数
(值最好大一点)。 - 把这个字符串的每个字符换成 ASCII 码,而把整个字符串看作一个
进制数,仍然以abcqwq
为例,它的哈希值为 。 - 用
unsigned long long
存储哈希值,这样就相当于自动取模 。
以上便是计算一个字符串的哈希值的方法。如果两个字符串的哈希值相同,一般来说这两个字符串就是相同的,但是有特殊情况——哈希冲突。因为哈希值是取模过的,因此一定会存在哈希值相同的字符串,也就是哈希冲突,对于这种情况,可以通过把
至于哈希如何解决字符串匹配问题,例如匹配一个字符串
再讨论一下二维情况,和一维情况下的字符串哈希值求法相似,对于字符矩阵的哈希值可以看作有着两个进制的数。那么这又是个什么概念呢?是这样的:所谓两个进制则是指从行和列两个维度转移时的“进制”要不相同,否则哈希冲突的概率很大。具体计算方案如下:
- 首先是一个字符矩阵
(所有字符仍全部为小写字母)。比如:
a |
b |
---|---|
q |
w |
-
设定两个质数
(进制一)与 (进制二),最好一个大一个稍小。 -
以上图矩阵为例,其哈希值为
。 -
仍用
unsigned long long
存储哈希值。
回到原问题中:如何解决矩阵匹配问题。与字符串匹配相似,仍是以递推的形式计算原矩阵
那么至此,我们就已经可以通过枚举
然后给出代码
#include<bits/stdc++.h> using namespace std; char s[1010][1010],s2[1010][1010]; int n,m,n2,m2,ans,t; unsigned long long h[1010][1010],h2[1010][1010],q1[1020100],q2[1020100],p1=40000021,p2=997; int main() { q1[0]=q2[0]=1;//零次方为1。 for(int i=1;i<1020100;i++) q1[i]=q1[i-1]*p1,q2[i]=q2[i-1]*p2;//预处理p1、p2的幂。 scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%s",s[i]); for(int i=0;i<n;i++) for(int j=0;j<m;j++) h[i+1][j+1]=h[i][j+1]*p1+h[i+1][j]*p2-h[i][j]*p1*p2+s[i][j];//计算原矩阵的每个子矩阵的哈希值。 scanf("%d%d",&n2,&m2); for(int i=0;i<n2;i++) scanf("%s",s2[i]); for(int i=0;i<n2;i++) for(int j=0;j<m2;j++) h2[i+1][j+1]=h2[i][j+1]*p1+h2[i+1][j]*p2-h2[i][j]*p1*p2+s2[i][j];//计算模式矩阵的哈希值。 ans=0; for(int i=0;i<n-n2+1;i++) for(int j=0;j<m-m2+1;j++)//在原矩阵中枚举与模式矩阵同样大小的子矩阵。 if(h[i+n2][j+m2]-h[i][j+m2]*q1[n2]-h[i+n2][j]*q2[m2]+h[i][j]*q1[n2]*q2[m2]==h2[n2][m2]) ans++; printf("%d\n",ans); } return 0; }
update
本文最初发布于 2021.08.17,其时本人还未上初中,用语多有不严谨、幼稚之处,Latex 也有使用错误。经众多网友反馈,于 2023.8.29 修改重新上传。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端