您的位置:首页 > 其它

UVA 11019 Matrix Matcher( 二维字符匹配 AC自动机 + DP)

2013-10-18 22:41 417 查看
题目大意:给你n*m的一个字符T矩阵,和一个x*y的字符P矩阵,让你找出P矩阵在T矩阵中出现了几次。

思路:把P矩阵一行一行插进去AC自动机,设 cc[ i ][ j ] 表示以T矩阵的第 i 行,第 j 列为左上顶点与P矩阵最多的匹配行数,

那么如果在匹配过程中匹配到的字符是P的某一行末尾的字符,那么就在对应的左上顶点的 cc ++ 即可。最后统计一遍所有顶点的cc,

cc == x 的数量即为匹配次数。这里还有一点需要注意,由于构造AC自动机时,如果两个字符串相同,后面的字符串会覆盖掉前面的,

也就是说 trie 中某个节点可能对应几个P中字符串的结尾,所以这里我直接用 vector 来存 val 信息了。
这题说实话这题自己想的时候,没有思路,看了书上的思路才写的,发现AC自动机好多都和DP结合起来,这题赞一个!
错了两次才AC的,第一遍是RE,可能是由于我把变量都开在 struct 里的原因,以后干脆直接就放外面好了,之后 WA 了,然后对照模板,发现原来是

get_fail 那里的 while 我把 !ch[ pre ][ i ] 写成 ch[ pre ][ i ]了,又是小细节问题。幸好改过来后就直接A了。。 = =
代码如下:

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

const int MAX_NODE = 11111;

const int SIGMA_SIZE = 26;

char t[1111][1111],p[111][111];

int cc[1111][1111];

int ch[MAX_NODE][SIGMA_SIZE];
int fail[MAX_NODE];
int tot;
vector <int> val[MAX_NODE];

struct Ac
{

void init()
{
memset(ch[0],0,sizeof(ch[0]));
tot = 1;
val[0].clear();
}
int idx(char c)
{
return c - 'a';
}
void insert(char *s,int len,int id)
{
int u = 0;
for(int i = 0;i<len;i++)
{
int c = idx(s[i]);
if(!ch[u][c])
{
memset(ch[tot],0,sizeof(ch[tot]));
val[tot].clear();
ch[u][c] = tot++;
}
u = ch[u][c];
}
val[u].push_back(id);
}
void get_fail()
{
fail[0] = 0;
queue <int> q;
for(int i = 0;i<SIGMA_SIZE;i++)
if(ch[0][i])
{
fail[ch[0][i]] = 0;
q.push(ch[0][i]);
}
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = 0;i<SIGMA_SIZE;i++)
{
int v = ch[u][i];
if(!v)
{
ch[u][i] = ch[fail[u]][i];
continue;
}
q.push(v);
int j = fail[u];
while(j && !ch[j][i]) j = fail[j];
j = ch[j][i];
fail[v] = j;
}
}
}
int find(int x,int y,int n,int m)
{
memset(cc,0,sizeof(cc));
int pre = 0;
for(int i = 1;i<=n;i++)
for(int j = 0;j<m;j++)
{
int c = idx(t[i][j]);
pre = ch[pre][c];
for(int pos = 0;pos < val[pre].size();pos ++)
{
int ii = i - (val[pre][pos] - 1);
int jj = j - (y - 1);
cc[ii][jj]++;
}
}
int ans = 0;
for(int i = 1;i<=n;i++)
for(int j = 0;j<m;j++)
if(cc[i][j] == x)
ans ++;
return ans;
}
}ac;

int main()
{
int _;
scanf("%d",&_);
while(_--)
{
ac.init();
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;i++)
scanf("%s",t[i]);
int x,y;
scanf("%d%d",&x,&y);
for(int i = 1;i<=x;i++)
{
scanf("%s",p[i]);
ac.insert(p[i],y,i);
}
ac.get_fail();
printf("%d\n",ac.find(x,y,n,m));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: