您的位置:首页 > 其它

UVa 11019 (AC自动机 二维模式串匹配) Matrix Matcher

2015-04-05 20:47 197 查看
就向书上说得那样,如果模式串P的第i行出现在文本串T的第r行第c列,则cnt[r-i][c]++;

还有个很棘手的问题就是模式串中可能会有相同的串,所以用repr[i]来记录第i个模式串P[i]第一次出现的位置。如果repr[i] == i,说明这个模式串之前没有重复过,可以加进自动机里去。有重复的话,把这些重复的模式串组织成一个链表,用next把它们连接起来。

所以在统计cnt的时候,匹配到的模式串可能会作为匹配的第i行,也可能是next[i]行,next[next[i]]行等等。

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

int n, m, x, y, tr;
const int maxx = 100 + 10;
const int maxn = 1000 + 10;
const int maxnode = 10000 + 10;
const int sigma_size = 26;
char T[maxn][maxn], P[maxx][maxx];
int cnt[maxn][maxn];
int repr[maxx];
int next[maxx];

struct AhoCorasickAutomata
{
int ch[maxnode][sigma_size];
int f[maxnode];
int last[maxnode];
int val[maxnode];
int sz;

void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }

inline int idx(char c) { return c - 'a'; }

void insert(char* s, int v)
{
int u = 0, n = strlen(s);
for(int i = 0; i < n; i++)
{
int c = idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}

void match(int i, int j)
{
int c = i - y + 1;
int pr = repr[val[j] - 1];
while(pr >= 0)
{
if(tr - pr >= 0) cnt[tr-pr][c]++;
pr = next[pr];
}
}

void print(int i, int j)
{//在文本串的第i列匹配到单词节点j
if(j)
{
match(i, j);
print(i, last[j]);
}
}

void find(char* T)
{
int j = 0, n = strlen(T);
for(int i = 0; i < n; i++)
{
int c = idx(T[i]);
while(j && !ch[j][c]) j = f[j];
j = ch[j][c];
if(val[j]) print(i, j);
else if(val[last[j]]) print(i, last[j]);
}
}

void getFail()
{
queue<int> q;
f[0] = 0;
for(int c = 0; c < sigma_size; c++)
{
int u = ch[0][c];
if(u) { f[u] = 0; last[u] = 0; q.push(u); }
}
while(!q.empty())
{
int r = q.front(); q.pop();
for(int c = 0; c < sigma_size; c++)
{
int u = ch[r][c];
if(!u) continue;
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
}ac;

int main()
{
//freopen("in.txt", "r", stdin);

int test;
scanf("%d", &test);
while(test--)
{
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) scanf("%s", T[i]);
scanf("%d%d", &x, &y);
ac.init();
for(int i = 0; i < x; i++)
{
repr[i] = i;
next[i] = -1;
scanf("%s", P[i]);
for(int j = 0; j < i; j++) if(strcmp(P[i], P[j]) == 0)
{
repr[i] = j;
next[i] = next[j];
next[j] = i;
break;
}
if(repr[i] == i) ac.insert(P[i], i+1);
}
ac.getFail();
memset(cnt, 0, sizeof(cnt));
for(tr = 0; tr < n; tr++) ac.find(T);

int ans = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(cnt[i][j] == x) ans++;
printf("%d\n", ans);
}

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: