字符创匹配(Rabin-Karp 算法)(hash)

<span style="font-size:18px;">//题目链接:http://poj.org/problem?id=3690

//复杂度:如果一一检查,会退化为O(mn) 不同字符串哈希值冲突的概率非常低,
//通常可以忽视,实际不做朴素的检查,所以是O(m+n)。

//哈希函数:H(C)=(c1*pow(b,m-1)+c2*pow(b,m-2)+c3*pow(b,m-3)+...+cm*pow(b,0))mod h.(b为哈希的基数)
//递推:H(S[k+1...k+m])=( H(S[k...k+m-1])*b-sk*pow(b,m)+sk+m )mod h
//取h=pow(2,64),用自然溢出省去模运算

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
typedef unsigned long long ull;
const int maxn=1005,maxt=105;

const ull b1=9973,b2=100000007;
ull tmp[maxn][maxn],Hash[maxn][maxn];
char field[maxn][maxn],model[maxt][maxn][maxn];
multiset<ull> mul;
int P,Q;

void solve(char M[maxn][maxn],int r,int c)
{
   int i,j;
   ull t=1,e;
   for(i=0;i<Q;i++)t*=b1;
   for(i=0;i<r;i++)
   {
      e=0;
      for(j=0;j<Q;j++)
      {
         e=e*b1+M[i][j];
      }
      for(j=0;j+Q<=c;j++)
      {
         tmp[i][j]=e;
         if(j+Q<c)
         {
            e=e*b1-M[i][j]*t+M[i][j+Q];
         }
      }
   }
   t=1;
   for(i=0;i<P;i++)t*=b2;
   for(i=0;i<c-Q+1;i++)
   {
      e=0;
      for(j=0;j<P;j++)
      {
         e=e*b2+tmp[j][i];
      }
      for(j=0;j+P<=r;j++)
      {
         Hash[j][i]=e;
         if(j+P<r)
         {
            e=e*b2-tmp[j][i]*t+tmp[j+P][i];
         }
      }
   }
}

int main()
{
   int N,M,T,i,j,kase=1;
   while(scanf("%d%d%d%d%d",&N,&M,&T,&P,&Q)!=EOF)
   {
      mul.clear();
      if(N==0 && M==0 && T==0 && P==0 && Q==0)break;
      getchar();
      for(i=0;i<N;i++) scanf("%s",field[i]);
      for(i=0;i<T;i++)
      {
         getchar();
         for(j=0;j<P;j++)
         {
            scanf("%s",model[i][j]);
         }
      }
      for(i=0;i<T;i++)
      {
         solve(model[i],P,Q);
         mul.insert(Hash[0][0]);
      }
      solve(field,N,M);
      for(i=0;i<N-P+1;i++)
      {
         for(j=0;j<M-Q+1;j++)
         {
            mul.erase(Hash[i][j]);
         }
      }
      printf("Case %d: %d\n",kase++,T-mul.size());
   }
   return 0;
}

</span>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值