UVA 11019 Matrix Matcher AC自动机字符串矩阵匹配

题目大意:

就是在给出的N*M(1 <= N, M <= 1000) 的字符矩阵中寻找子矩阵X*Y(1 <= X, Y <= 100)出现的次数


大致思路:

白书例题= =

不过这种统计出现位置的方法还真是巧妙....需要注意当把X*Y的矩阵拆解的时候可能出现多行是一样的情况

细节见注释吧...


代码如下:

Result  :  Accepted     Memory  :  ? KB     Time  :  2095 ms

/*
 * Author: Gatevin
 * Created Time:  2015/2/12 13:39:53
 * File Name: Mononobe_Mitsuki.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

int N, M, X, Y;
char all[1010][1010];
char pat[110];
int match[1010][1010];

/*
 * 白书例题
 * 用match[i][j]表示以(i, j)为左上角大小为X*Y的矩阵与模板矩阵X*Y有多少行匹配成功
 * 先将子矩阵的各个行拆开插入Trie树建立AC自动机, 然后对于N*M矩阵的每行进行一次遍历
 * 如果N*M矩阵的从第r行c列开始长度为Y的串出现匹配,则对与匹配到的原X*Y矩阵中的第k行
 * 则将match[r][c - k + 1]加1, 就是这个地方的匹配位置统计感觉挺巧妙的
 */
struct Trie
{
    int next[10010][26], fail[10010];
    vector <int> end[10010];//因为可能出现X*Y的矩阵中多个横行相同的情况,匹配位置需要用vector
    int L, root;
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            next[L][i] = -1;
        end[L++].clear();
        return L - 1;
    }
    void init()
    {
        L = 0;
        root = newnode();
        return;
    }
    void insert(char *s, int id)
    {
        int now = root;
        for(; *s; s++)
        {
            if(next[now][*s - 'a'] == -1)
                next[now][*s - 'a'] = newnode();
            now = next[now][*s - 'a'];
        }
        end[now].push_back(id);
        return;
    }
    void build()
    {
        fail[root] = root;
        queue <int> Q;
        Q.push(root);
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0; i < 26; i++)
                if(next[now][i] == -1)
                    next[now][i] = now == root ? root : next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = now == root ? root : next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
        return;
    }
    void query(char *s, int row)
    {
        int now = root;
        for(int col = 0; col < M; col++)
        {
            now = next[now][s[col] - 'a'];
            int tmp = now;
            while(tmp != root)
            {
                if(!end[tmp].empty())//第row行col - Y + 1列处出现了要找的子矩阵的end[tmp][i]列
                    for(unsigned int i = 0; i < end[tmp].size(); i++)
                        if(row + 1 >= end[tmp][i])
                            match[row - end[tmp][i] + 1][col - Y + 1]++;
                tmp = fail[tmp];
            }
        }
        return;
    }
    void solve()
    {
        memset(match, 0, sizeof(match));
        for(int i = 0; i < N; i++)
            query(all[i], i);
        int ans = 0;
        for(int i = 0; i < N; i++)
            for(int j = 0; j < M; j++)
                if(match[i][j] == X)
                    ans++;
        printf("%d\n", ans);
        return;
    }
};

Trie AC;

int main()
{
    int t;
    scanf("%d", &t);
    while(t-->0)
    {
        scanf("%d %d", &N, &M);
        AC.init();
        for(int i = 0; i < N; i++)
            scanf("%s", all[i]);
        scanf("%d %d", &X, &Y);
        for(int i = 1; i <= X; i++)
            scanf("%s", pat), AC.insert(pat, i);
        AC.build();
        AC.solve();
    }
    return 0;
}


你可能感兴趣的:(Matcher,Matrix,uva,AC自动机,11019,字符块匹配)