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

来源:互联网 发布:手机淘宝店铺如何改名 编辑:程序博客网 时间:2024/05/30 05:08
题目大意:给你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;}


原创粉丝点击