矩阵hash + KMP - UVA 12886 The Big Painting

简介: The Big Painting  Problem's Link:  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=88791   Mean:  给你两个由字符组成的矩阵,让你判断第一个矩阵在第二个矩阵中出现了多少次。

The Big Painting 

Problem's Link:  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=88791


 

Mean: 

给你两个由字符组成的矩阵,让你判断第一个矩阵在第二个矩阵中出现了多少次。

analyse:

典型的二维矩阵hash。

这题有两种做法:

第一种:横向hash,然后纵向KMP。时间复杂度是O(N*(N+M)).

第二种:二维hash。直接对两个矩阵做二维hash,然后判断大矩阵的子矩阵的hash值是否等于小矩阵的hash值,统计答案即可。

从实现上来说,二维hash更容易写,也更容易理解,但是我在比赛时忽略了一种情况:

 

1 2 2 4
xo
xoxo
oxox

正确答案是:3.

但如果我们在hash时,横向hash选取的种子值和纵向hash选取的种子值是相同的,就会出现错误,答案就变为了5。

这是因为本来答案只要统计横向的,但是由于横向和纵向的种子值相同,就会多统计进去两次纵向的。

如果题目说小矩形(或者大矩形)可以旋转匹配,那么种子值选取一样就对了。

 

 

Time complexity: 二维hash:O(N*M)    hash+KMP:O(N*(N+M))

 

Source code: 

二维hash:

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-08-10-08.37
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;
const int MAXN = 2010;
const ULL seed1 = 10000007;   // line   h
const ULL seed2 = 100000007; // row     w
int hp , wp , hm , wm;
char G1 [ MAXN ][ MAXN ], G2 [ MAXN ][ MAXN ];
ULL Tab1 [ MAXN ][ MAXN ], Tab2 [ MAXN ][ MAXN ], goal;

void GetHash()
{
      goal = 0;
      for( int i = 0; i < hp; ++ i)
      {
            ULL a = 0;
            for( int j = 0; j < wp; ++ j)
            {
                  a = a * seed2 + G1 [ i ][ j ];
            }
            goal = goal * seed1 + a;
      }
}


int solve()
{
      int ans = 0;
      ULL base1 = 1 , base2 = 1;
      for( int i = 0; i < hp; ++ i) base1 *= seed1;
      for( int i = 0; i < wp; ++ i) base2 *= seed2;
      for( int i = 0; i < hm; ++ i) // line
      {
            ULL a = 0;
            for( int j = 0; j < wp; ++ j) a = a * seed2 + G2 [ i ][ j ];
            Tab1 [ i ][ wp - 1 ] = a;
            for( int j = wp; j < wm; ++ j)
            {
                  Tab1 [ i ][ j ] = Tab1 [ i ][ j - 1 ] * seed2 + G2 [ i ][ j ] - base2 * G2 [ i ][ j - wp ];
            }
      }
      for( int i = wp - 1; i < wm; ++ i)
      {
            ULL a = 0;
            for( int j = 0; j < hp; ++ j) a = a * seed1 + Tab1 [ j ][ i ];
            Tab2 [ hp - 1 ][ i ] = a;
            if( a == goal) ++ ans;
            for( int j = hp; j < hm; ++ j)
            {
                  Tab2 [ j ][ i ] = Tab2 [ j - 1 ][ i ] * seed1 + Tab1 [ j ][ i ] - Tab1 [ j - hp ][ i ] * base1;
                  if( Tab2 [ j ][ i ] == goal) ++ ans;
            }
      }
      return ans;
}


int main()
{
      ios_base :: sync_with_stdio( false);
      cin . tie( 0);
      while( ~ scanf( "%d %d %d %d" , & hp , & wp , & hm , & wm))
      {
            getchar();
            for( int i = 0; i < hp; ++ i) gets( G1 [ i ]);
            for( int i = 0; i < hm; ++ i) gets( G2 [ i ]);
            GetHash();
            printf( "%d \n " , solve());
      }
      return 0;
}
/*

*/

 

hash+KMP:

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-08-09-13.27
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;

const int MAXN = 2010;
const ULL seed = 1000000007;
ULL base [ MAXN ];

ULL hashval [ MAXN ][ MAXN ], Ti [ MAXN ][ MAXN ], hashTmp [ MAXN ], val [ MAXN ];
int Next [ MAXN ], h , w ,n , m;
char s [ MAXN ][ MAXN ], t [ MAXN ][ MAXN ];

int KMP()
{
      int ans = 0;
      for( int i = 0 , j =- 1; i < m; ++ i)
      {
            while( j !=- 1 && val [ i ] != hashTmp [ j + 1 ]) j = Next [ j ];
            if( val [ i ] == hashTmp [ j + 1 ])
            {
                  if( ++ j == w - 1)
                  {
                        j = Next [ j ];
                        ans ++;
                  }
            }
      }
      return ans;
}


void init( char s [ MAXN ][ MAXN ], ULL hashval [ MAXN ][ MAXN ], int h , int w)
{
      for( int j = 0; j < w; ++ j)
      {
            hashval [ h ][ j ] = 0;
            for( int i = h - 1; i >= 0; -- i) hashval [ i ][ j ] = hashval [ i + 1 ][ j ] * seed +s [ i ][ j ];
      }
}


int solve()
{
      init(s , hashval , h , w);
      init( t , Ti ,n , m);
      for( int i = 0; i < w; ++ i)
      {
            hashTmp [ i ] = hashval [ 0 ][ i ];
      }
      // KMP Matching
      Next [ 0 ] =- 1;
//      puts("- - - - - - - - - - - Program Run Here ! - - - - - - - - - - - - ");

      for( int i = 1 , j =- 1; i < w; ++ i)
      {
            while( j !=- 1 && hashTmp [ i ] != hashTmp [ j + 1 ]) j = Next [ j ];
            Next [ i ] = hashTmp [ i ] == hashTmp [ j + 1 ] ? ++ j: j;
      }
//      for(int i=1;i<w;++i)
//      {
//            printf("%d",Next[i]);
//      }
      int ans = 0;
      for( int i = 0; i <n - h + 1; ++ i)
      {
            for( int j = 0; j < m; ++ j)
                  val [ j ] = Ti [ i ][ j ] - Ti [ i + h ][ j ] * base [ h ];
            ans += KMP();
      }
      return ans;
}

void _()
{
      base [ 0 ] = 1;
      for( int i = 1; i < MAXN; ++ i) base [ i ] = base [ i - 1 ] * seed;
}
int main()
{
      _();
      while( ~ scanf( "%d %d %d %d" , & h , & w , &n , & m))
      {
            getchar();
            for( int i = 0; i < h; ++ i) gets(s [ i ]);
            for( int i = 0; i <n; ++ i) gets( t [ i ]);
            printf( "%d \n " , solve());
      }
}

 

目录
相关文章
|
7月前
|
人工智能 算法 BI
D - Silver Cow Party——POJ3268(连续用两次Dijkstra算法)
D - Silver Cow Party——POJ3268(连续用两次Dijkstra算法)
|
算法
light oj 1255 - Substring Frequency (KMP)
输入两个字符串,计算二串在一串中出现的次数。 裸裸的KMP,参考刘汝佳《算法竞赛入门经典训练指南》 P212 或数据结构。
28 1
UVa11157 - Dynamic Frog(动态规划)
UVa11157 - Dynamic Frog(动态规划)
58 0
LeetCode contest 190 5418. 二叉树中的伪回文路径 Pseudo-Palindromic Paths in a Binary Tree
LeetCode contest 190 5418. 二叉树中的伪回文路径 Pseudo-Palindromic Paths in a Binary Tree
|
存储 算法 测试技术
UVA240 Variable Radix Huffman Encoding
UVA240 Variable Radix Huffman Encoding
UVA240 Variable Radix Huffman Encoding
SP10707 COT2 - Count on a tree II(欧拉序 树上莫队)
SP10707 COT2 - Count on a tree II(欧拉序 树上莫队)
117 0
SP10707 COT2 - Count on a tree II(欧拉序 树上莫队)
CF1272 E.Nearest Opposite Parity(反向建图+BFS)
CF1272 E.Nearest Opposite Parity(反向建图+BFS)
107 0
CF1272 E.Nearest Opposite Parity(反向建图+BFS)
|
机器学习/深度学习 存储 人工智能