UVA11019----AC自动机(要深刻理解)*

题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1960

题目意思:

给你一个n*m的字符矩阵

再给你一个x*y的字符矩阵

问你n*m的矩阵里面有多少个x*y的矩阵

我把这道题目理解为一道二维的AC自动机

首先对x*y的里面的每一行都作为一个模板建模

然后再对n*m的矩阵的每一行都作为母串来进行比对

根据大白上面说的我们构造一个cnt[r][c]二维数组,来表示以r,c为左上角的话已经比对模板有多少个了。

统计完了之后,再来查询每个cnt[r][c],如果比对的行数为x,即全部的模板行,那么就是一个,ans++

此题有几个很关键的地方

一个是统计函数,说实话,这题不看大白,我自己估计很难想出来

在统计的时候,拿到了一个匹配模板之后,

首先确定左上角,因为当前行是tr,所以左上角是tr-pr

仔细想一下,当tr变为下一行,而模板的下一行也匹配的话,那不就还是在左上角匹配吗,所以这个是十分巧妙的

再就是next数组,因为小的模板里面可能会有重复的模板行,所以插入的时候我们要只需在AC自动机里面插入一个

但是我们要记录那几个是一样的,所以就可以用next数组来记录,这一点在一次统计的时候,可以起到同时匹配多个模板行的作用。

下面上代码,这个我可是精心注释的哦,只有深刻理解每个算法,才能应付变化多端的题目。

#include
#include
#include
#include
using namespace std;

const int maxnode = 100*100+10;//最多的模板节点个数
const int size = 26;//最多的字符数,a~z

void process_match(int pos,int j);


struct AC{
    int ch[maxnode][size];//每个节点的后继节点
    int f[maxnode];//失配边
    int val[maxnode];//用来表示在模板中哪些是模板的结束点
    int last[maxnode];//输出某个节点相同的末尾节点
    int sz;//这颗trie的节点个数

    void init()//初始化函数
    {
        sz=1;
        memset(ch[0],0,sizeof(ch[0]));
    }

    int idx(char c)//将字符转换为相对应的数字,便于计算
    {
        return c-'a';
    }

    void insert(char *s,int v)//在这颗trie中插入一个模板s,并将它的末尾节点赋val为v
    {
        int u=0;
        int n=strlen(s);
        for(int i=0;iq;
        f[0]=0;

        for(int c=0;c= 0)//一个一个的去加,最后看有木有x个
    {
        if(tr >= pr) // P的行pr出现在在T的tr行,起始列编号为c
            cnt[tr - pr][c]++;
        pr = next[pr];//继续和下一个匹配的计算
    }
}

int main()
{
    int t;
    int ca=1;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i



你可能感兴趣的:(字符串)