poj1204

dfa,ac自动机。

题意:给定一些单词,给定一个矩阵,在矩阵内8方向找每个单词是否出现过。输出每个单词的出现位置和方向。

分析:分别以位于矩阵四周的点作为起点,每个起点找向8个方向最长的字符串,分别加入自动机。

View Code
#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

using namespace std;



const int kind = 26;

struct node

{

    node *fail; //失败指针

    node *next[kind]; //Tire每个节点的26个子节点(最多26个字母)

    int id; //是否为该单词的最后一个节点

    node()

    { //构造函数初始化

        fail = NULL;

        id = -1;

        memset(next, (int) NULL, sizeof(next));

    }

}*q[500001], *root; //队列,方便用于bfs构造失败指针

char str[1005]; //模式串



#define maxn 1005

#define maxl 305



int l, c, w;

char map[maxn][maxn];

char word[maxn][maxl];

int dir[8][2] =

{

{ -1, 0 },

{ -1, 1 },

{ 0, 1 },

{ 1, 1 },

{ 1, 0 },

{ 1, -1 },

{ 0, -1 },

{ -1, -1 } };

int ans[maxn][3];

bool vis[maxn];

int nowx, nowy, nowd;

int len[maxn];



void insert(char *str, node *root, int id)

{

    node *p = root;

    int i = 0, index;

    while (str[i])

    {

        index = str[i] - 'A';

        if (p->next[index] == NULL)

            p->next[index] = new node();

        p = p->next[index];

        i++;

    }

    p->id = id;

}

void build_ac_automation(node *root)

{

    int i;

    int head, tail; //队列的头尾指针

    head = tail = 0;

    root->fail = NULL;

    q[head++] = root;

    while (head != tail)

    {

        node *temp = q[tail++];

        node *p = NULL;

        for (i = 0; i < 26; i++)

        {

            if (temp->next[i] != NULL)

            {

                p = temp->fail;

                while (p != NULL && p->next[i] == NULL)

                    p = p->fail;

                if (p == NULL)

                    temp->next[i]->fail = root;

                else

                    temp->next[i]->fail = p->next[i];

                q[head++] = temp->next[i];

            }

        }

    }

}



void makeans(int id, int pos)

{

    vis[id] = true;

    ans[id][0] = nowx + dir[nowd][0] * (pos - len[id] + 1);

    ans[id][1] = nowy + dir[nowd][1] * (pos - len[id] + 1);

    ans[id][2] = nowd;

}



int query(node *root, char* str)

{

    int i = 0, cnt = 0, index;

    node *p = root;

    while (str[i])

    {

        index = str[i] - 'A';

        while (p->next[index] == NULL && p != root)

            p = p->fail;

        p = p->next[index];

        p = (p == NULL) ? root : p;

        node *temp = p;

        while (temp != root)

        {

            if (temp->id != -1 && !vis[temp->id])

                makeans(temp->id, i);

            temp = temp->fail;

        }

        i++;

    }

    return cnt;

}



void input()

{

    scanf("%d%d%d", &l, &c, &w);

    for (int i = 0; i < l; i++)

        scanf("%s", map[i]);

    for (int i = 0; i < w; i++)

    {

        scanf("%s", word[i]);

        insert(word[i], root, i);

        len[i] = strlen(word[i]);

    }

}



bool ok(int x, int y)

{

    return x >= 0 && y >= 0 && x < l && y < c;

}



void make(int x, int y, int d)

{

    int i = 0;

    nowx = x;

    nowy = y;

    nowd = d;

    while (ok(x, y))

    {

        str[i++] = map[x][y];

        x += dir[d][0];

        y += dir[d][1];

    }

    str[i] = 0;

    query(root, str);

}



void work()

{

    build_ac_automation(root);

    memset(vis, 0, sizeof(vis));

    for (int i = 0; i < l; i++)

        for (int j = 0; j < 8; j++)

        {

            make(i, 0, j);

            make(i, c - 1, j);

        }

    for (int i = 0; i < c; i++)

        for (int j = 0; j < 8; j++)

        {

            make(0, i, j);

            make(l - 1, i, j);

        }

    for (int i = 0; i < w; i++)

        printf("%d %d %c\n", ans[i][0], ans[i][1], (char) (ans[i][2] + 'A'));

}



int main()

{

    //freopen("t.txt", "r", stdin);

    root = new node();

    input();

    work();

    return 0;

}

你可能感兴趣的:(poj)