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;
}
posted @ 2012-07-11 18:12  金海峰  阅读(1128)  评论(0编辑  收藏  举报