您的位置:首页 > 其它

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

2015-02-12 14:19 405 查看
题目大意:

就是在给出的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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息