您的位置:首页 > 其它

Uva11019——二维字符串匹配

2013-03-09 16:46 831 查看
题意:给出两个字符串矩阵A1,A2判断A2在A1中出现多少次。

思路还是很明确的,而且很容易想到:用A2的每一行字符构造ac自动机,然后去匹配A1的每一行字符,每一次匹配到了单词节点,则在A1中将该字符标记(可以用一个二维数组保存标记),一旦匹配到了A2的最后一行的单词节点,则回头去检测在A1中相同列的连续的若干行中的字符的标记是否满足要求。而且由于ac自动机中每一个单词的长度都是一样的,所以不需要考虑某个单词节点的失配指针路径上是否有单词节点(肯定没有)。

还有一个要处理的问题:A2当中可能出现的相同的行,那么对应构造的ac自动机中前面行的单词节点会被后面的覆盖,因此在匹配A1的每一行时,若碰到单词节点,标记的肯定是与之匹配的A2种行号最大的那一行,那么在返回检测的时候,就有可能误判。我的做法是有数组trans[i]表示A2中与行i相同的行号最大的那一行的行数,在向ac自动机中插入字符串标记单词节点的时候,注意判断一下该节点是否已经是单词节点,如果是更新一下trans数组。

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

const int maxn = 10000 + 50;
const int sigma_size = 128;
int mark[1005][1005], m, n, x, y, trans[1000], res;
char str[1005][1005];

struct ac_machine
{
int ch[maxn][sigma_size];
int val[maxn];
int f[maxn];
int sz;
void init() { sz = 1; memset(ch, 0, sizeof(ch)); memset(val, 0, sizeof(val)); memset(f, 0, sizeof(f)); }
int idx(char c)
{
return c - '\0';
}

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

void getFail()
{
queue<int> q;
f[0] = 0;
for(int i = 0; i < sigma_size; ++i)
{
if(ch[0][i]) { q.push(ch[0][i]); f[ch[0][i]] = 0; }
else ch[0][i] = 0;
}
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 0; i < sigma_size; ++i)
{
int v = ch[u][i];
if(v)
{
q.push(v);
int p = f[u];
while(p && ch[p][i] == 0) p = f[p];
f[v] = ch[p][i];
}
else ch[u][i] = ch[f[u]][i];
}
}
}

void find()
{
for(int a = 0; a < m; ++a)
{
int u = 0;
for(int i = 0; i < n; ++i)
{
int c = idx(str[a][i]);
u = ch[u][c];
if(val[u])
{
mark[a][i] = val[u];
if(val[u] == x && a >= x - 1)
{
//cout << a << " " << i << "\n";
bool sign = true;
for(int j = a, k = x; k > 0; --k, --j)
if(mark[j][i] != trans[k]) { sign = false; break; }
if(sign) res++;
}
}
}
}
}

}ac;

int main()
{
freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while(t--)
{
res = 0; ac.init();
for(int i = 1; i <= 100; ++i) trans[i] = i;
memset(mark, 0, sizeof(mark));
scanf("%d %d", &m, &n);
for(int i = 0; i < m; ++i)
scanf("%s", str[i]);
scanf("%d %d", &x, &y);
for(int i = 0; i < x; ++i)
{
char tempstr[104];
scanf("%s", tempstr);
ac.insert(tempstr, i + 1);
}
ac.getFail();
ac.find();
printf("%d\n", res);
}
return 0;
}

/*
2
1 1
x
1 1
y
3 3
abc
bcd
cde
2 2
bc
cd

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