poj 1204 Word Puzzles

题目来源:http://poj.org/problem?id=1204

题意:给你一个矩阵,矩阵里面存放着一些字符,问给出的字符串,是否在矩阵中,并判断在该字符串的首个字符在矩阵中的位置,以及该字符串的方向(可以看一下样例,就明白了).

正北标记为'A',东北标记为'B',类似以顺时针并按字典序标记方向,即到'H'表示西北方向。

ac自动机来做的,事实上,这个题还可以利用深搜来求解。

ac自动机比较好的参考资料:http://download.csdn.net/detail/hearthougan/7316089

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 1010;

struct Trie_Node
{
    int index;
    Trie_Node* pNext[26];
    Trie_Node* pFail;
    Trie_Node()
    {
        index = 0;
        memset(pNext, NULL, sizeof(pNext));
        pFail = NULL;
    }
};

Trie_Node* pRoot;
Trie_Node* Q[MAXN*100];
char Graph[MAXN][MAXN];
int row, col;

int dir[8][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};//这一块需要注意,数组的方向跟实际坐标的方向是不一样的
int Len[MAXN], res[MAXN][3];

bool IsCanGo(int x, int y)
{
    if(x < 0 || x >= row || y < 0 || y >= col)
        return false;
    return true;
}

void Build_Trie(char* str, int id)//建立字典树
{
    int j, i = 0;
    Trie_Node* p = pRoot;
    while(str[i])
    {
        j = str[i++] - 'A';
        if(p->pNext[j] == NULL)
            p->pNext[j] = new Trie_Node;
        p = p->pNext[j];
    }
    p->index = id;
}

void Build_Fail()//建立失败指针
{
    Trie_Node* tmp;
    Trie_Node* p;
    int qs = 0, qe = 0, i;
    Q[qe++] = pRoot;
    pRoot->pFail = NULL;
    while(qs < qe)
    {
        tmp = Q[qs++];
        p = NULL;
        for(i = 0; i < 26; ++i)
        {
            if(tmp->pNext[i] != NULL)
            {
                if(tmp == pRoot)
                    tmp->pNext[i]->pFail = pRoot;
                else
                {
                    p = tmp->pFail;
                    while(p != NULL)
                    {
                        if(p->pNext[i] != NULL)
                        {
                            tmp->pNext[i]->pFail = p->pNext[i];
                            break;
                        }
                        p = p->pFail;
                    }
                    if(p == NULL)
                        tmp->pNext[i]->pFail = pRoot;
                }
                Q[qe++] = tmp->pNext[i];
            }
        }
    }
}


void Query_Trie(int x, int y, int d)//查询
{
    int j;
    Trie_Node* p = pRoot;
    Trie_Node* tmp;
    while(IsCanGo(x, y))//多模同时匹配
    {
        j = Graph[x][y] - 'A';
        while(p->pNext[j] == NULL && p != pRoot)//如果p是指向叶子节点,那么就找他的失败指针指向的结点
            p = p->pFail;
        p = p->pNext[j] == NULL ? pRoot : p->pNext[j];
        tmp = p;//所谓多模同时匹配,关键点就是在这里,每到达一个节点,就查看它的失败指针指向的节点,是否也是一个单词的结尾
        while(tmp != pRoot && tmp->index > 0)
        {
            res[tmp->index][0] = x - Len[tmp->index]*dir[d][0];//模式串所在位置的横、纵坐标
            res[tmp->index][1] = y - Len[tmp->index]*dir[d][1];
            res[tmp->index][2] = d;//搜寻的方向
            tmp->index = 0;
            tmp = tmp->pFail;
        }
        x = x + dir[d][0];
        y = y + dir[d][1];
    }
}

void Delete_Trie(Trie_Node* p)
{
    int i;
    Trie_Node* tmp = p;
    for(i = 0; i < 26; ++i)
        if(tmp->pNext[i])
            Delete_Trie(tmp->pNext[i]);
    delete tmp;
}

int main()
{
    int subnum, i, j;
    char str[MAXN];
    while(~scanf("%d %d %d", &row, &col, &subnum))
    {
        pRoot = new Trie_Node;
        memset(res, 0, sizeof(res));
        for(i = 0; i < row; ++i)
            scanf("%s", Graph[i]);
        for(i = 1; i <= subnum; ++i)
        {
            scanf("%s", str);
            Len[i] = strlen(str)-1;
            Build_Trie(str, i);
        }
        Build_Fail();
        for(i = 0; i < row; ++i)//按每一行的字符串进行匹配
        {
            for(j = 0; j < 8; ++j)
            {
                Query_Trie(i, 0, j);//正着扫一下
                Query_Trie(i, col-1, j);//反着扫一下
            }
        }
        for(i = 0; i < col; ++i)
        {
            for(j = 0; j < 8; ++j)
            {
                Query_Trie(0, i, j);
                Query_Trie(row-1, i, j);
            }
        }
        for(i = 1; i <= subnum; ++i)
            printf("%d %d %c\n", res[i][0], res[i][1], res[i][2]+'A');
        Delete_Trie(pRoot);
    }
    return 0;
}


你可能感兴趣的:(AC自动机)