字符串hash(二维)-poj3690

来源:互联网 发布:手机淘宝怎样修改星评 编辑:程序博客网 时间:2024/05/01 19:43
Language:
Constellations
Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 4758 Accepted: 904

Description

The starry sky in the summer night is one of the most beautiful things on this planet. People imagine that some groups of stars in the sky form so-called constellations. Formally a constellation is a group of stars that are connected together to form a figure or picture. Some well-known constellations contain striking and familiar patterns of bright stars. Examples are Orion (containing a figure of a hunter), Leo (containing bright stars outlining the form of a lion), Scorpius (a scorpion), and Crux (a cross).

In this problem, you are to find occurrences of given constellations in a starry sky. For the sake of simplicity, the starry sky is given as a N × M matrix, each cell of which is a '*' or '0' indicating a star in the corresponding position or no star, respectively. Several constellations are given as a group of T P × Q matrices. You are to report how many constellations appear in the starry sky.

Note that a constellation appears in the sky if and only the corresponding P × Q matrix exactly matches some P × Q sub-matrix in the N × M matrix.

Input

The input consists of multiple test cases. Each test case starts with a line containing five integers N, M, T, P and Q(1 ≤ N, M ≤ 1000, 1 ≤ T ≤ 100, 1 ≤ P, Q ≤ 50). 
The following N lines describe the N × M matrix, each of which contains M characters '*' or '0'.
The last part of the test case describe T constellations, each of which takes P lines in the same format as the matrix describing the sky. There is a blank line preceding each constellation.
The last test case is followed by a line containing five zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the number of constellations appearing in the sky.

Sample Input

3 3 2 2 2*000***00**00*0**3 3 2 2 2*000***00**00*00*0 0 0 0 0

Sample Output

Case 1: 1Case 2: 2方法一:首先把一行看成一个字符串,计算出hash值,然后再把得到的hash值在列方向上看成字符串,计算hsah值代码如下:
#include<iostream>#include<set>#include<map>#include<vector>#include<queue>#include<cmath>#include<climits>#include<cstdio>#include<string>#include<cstring>#include<algorithm>typedef long long LL;using namespace std;const int MAX=1110;const int MAX_T=110;const int B1=9973;const int B2=100000007;int N,M,T,P,Q;int loop=1;char field[MAX][MAX];char patterns[MAX_T][MAX][MAX];LL hash[MAX][MAX],tmp[MAX][MAX];void compute_hash(char a[][MAX],int n,int m){    LL t1=1;    for(int i=0; i<Q; i++)        t1*=B1;    for(int i=0; i<n; i++)    {        LL e=0;        for(int j=0; j<Q; j++)            e=e*B1+a[i][j];        for(int j=0; j+Q<=m; j++)        {            tmp[i][j]=e;            if(j+Q<m)                e=e*B1-t1*a[i][j]+a[i][j+Q];        }    }    LL t2=1;    for(int i=0; i<P; i++)        t2*=B2;    for(int i=0; i+Q<=m; i++)    {        LL e=0;        for(int j=0; j<P; j++)            e=e*B2+tmp[j][i];        for(int j=0; j+P<=n; j++)        {            hash[j][i]=e;            if(j+P<n)                e=e*B2-t2*tmp[j][i]+tmp[j+P][i];        }    }}void solve(){    multiset<LL> uuseen;    for(int i=0; i<T; i++)    {        compute_hash(patterns[i],P,Q);        uuseen.insert(hash[0][0]);    }    compute_hash(field,N,M);    for(int i=0; i+P<=N; i++)    {        for(int j=0; j+Q<=M; j++)            uuseen.erase(hash[i][j]);    }    int ans=T-uuseen.size();    printf("Case %d: %d\n", loop++, ans);}int main(){    //freopen("in.txt","r",stdin);    while(scanf("%d%d%d%d%d",&N,&M,&T,&P,&Q)!=EOF)    {        if(!P&&!Q&&!T&&!N&&!M)            break;        for(int i=0; i<N; i++)        {            scanf("%s",field[i]);        }        for(int i=0; i<T; i++)        {            for(int j=0; j<P; j++)            {                scanf("%s",patterns[i][j]);            }        }        solve();    }    return 0;}

方法2:位运算计算每一行的hash值,然后一行一行的匹配。
代码如下:
#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio>#include <cmath>#include <queue>#include <map>#include <set>#define MAXN 111111#define MAXM 555555#define INF 100000011#define lch(x) x<<1#define rch(x) x<<1|1#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define eps 1e-7using namespace std;long long h[1111][1111];int n, m, t, p, q;char mp[1111][1111], tmp[66];long long a[66];bool ok(){    for(int i = 0; i + p - 1 < n; i++)        for(int j = q - 1; j < m; j++)        {            int flag = 1;            for(int k = 0; k < p; k++)                if(h[i + k][j] != a[k])                {                    flag = 0;                    break;                }            if(flag) return true;        }    return false;}int main(){    int cas = 0;    while(scanf("%d %d %d %d %d", &n, &m, &t, &p, &q) != EOF)    {        if(!n && !m && !t && !q && !p) break;        for(int i = 0; i < n; i++) scanf("%s", mp[i]);        memset(h, 0, sizeof(h));        for(int i = 0; i < n; i++)            for(int j = 0; j < q; j++)            {                if(mp[i][j] == '*') h[i][q - 1] |= (1LL << j);            }        for(int i = 0; i < n; i++)            for(int j = q; j < m; j++)            {                if(mp[i][j - q] == '*') h[i][j] = h[i][j - 1] - 1LL;                else h[i][j] = h[i][j - 1];                h[i][j] >>= 1LL;                if(mp[i][j] == '*') h[i][j] |= (1LL << (q - 1));            }        int cnt = 0;        while(t--)        {            for(int i = 0; i < p; i++)            {                scanf("%s", tmp);                a[i] = 0;                for(int j = 0; j < q; j++)                    if(tmp[j] == '*') a[i] |= (1LL << j);            }            if(ok()) cnt++;        }        printf("Case %d: %d\n", ++cas, cnt);    }    return 0;}