SPOJ WPUZZLES (POJ 1204) 413.Word Puzzles AC自动机

来源:互联网 发布:ionic lab mac 下载 编辑:程序博客网 时间:2024/05/20 04:28

POJ 1204 和SPOJ WPUZZLES一样..换了一下输入输出格式而已..

题目大意:

就是现在有一个游戏,给你一个L*C的字符块,只包含大写英文字母,现在你要在这个块中找到给出的所有的英语单词的位置和摆放方向。

其中要找的单词在块中只出现一次,(实际上多个要找的块不会重合,这个游戏就是这样...)

对于每个要找的字符串,输出其在块中起始位置的坐标和方向,方向只有8种,并且单词摆放不会拐弯..就是一条线摆放


大致思路:

其实就是个简单的模板题...首先将所有要找的字符串建立AC自动机,标号其结尾点,然后枚举矩阵的所有串,当然起点和重点都是边界,实际上要枚举的串并不多,找到串的时候利用串的长度和方向就可以很快算出起点位置,最后输出就可以了...


代码如下:

Result  :  Accepted     Memory  :  113664 KB     Time  :  320 ms

/* * Author: Gatevin * Created Time:  2014/11/26 15:30:39 * File Name: Kagome.cpp */#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;int t;int R, C, W;char m[1001][1001];char s[1001];int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1}; int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};struct Ans{    int x, y, dir;};Ans ans[1001];int len[1001];int next[1000001][26], fail[1000001], end[1000001];struct Trie{    int L, root;    int newnode()    {        for(int i = 0; i < 26; i++)            next[L][i] = -1;        end[L++] = -1;//end[i] = -1表示点i不是字符串结尾点        return L - 1;    }    void init()    {        L = 0;        root = newnode();        return;    }    void insert(char* in, int id)    {        int now = root;        for(; *in; in++)        {            if(next[now][*in - 'A'] == -1)                next[now][*in - 'A'] = newnode();            now = next[now][*in - 'A'];        }        end[now] = id;        return;    }    void build()    {        fail[root] = root;        queue <int> Q;        Q.push(root);        while(!Q.empty())        {            int now = Q.front();            Q.pop();            for(int i = 0; i < 26; i++)                if(next[now][i] == -1)                    next[now][i] = now == root ? root : next[fail[now]][i];                else                {                    fail[next[now][i]] = now == root ? root : next[fail[now]][i];                    Q.push(next[now][i]);                }        }        return;    }    void find(int x, int y, int dir)    {        int now = root;        while(x >= 0 && y >= 0 && x < R && y < C)        {            now = next[now][m[x][y] - 'A'];            /*             * 由于是字符块游戏,不会出现两块有重叠部分出现的情况             * 所以这里可以不用while(tmp != root) tmp = fail[tmp];这一段             */            if(end[now] >= 0)//找到字符串了            {                ans[end[now]].x = x - (len[end[now]] - 1)*dx[dir];//计算起点位置                ans[end[now]].y = y - (len[end[now]] - 1)*dy[dir];                ans[end[now]].dir = dir;            }            x += dx[dir];            y += dy[dir];        }        return;    }};Trie AC;int main(){    scanf("%d", &t);    while(t--)    {        AC.init();        scanf("%d %d %d", &R, &C, &W);        for(int i = 0; i < R; i++)            scanf("%s", m[i]);        for(int i = 0; i < W; i++)        {            scanf("%s", s);            AC.insert(s, i);            len[i] = strlen(s);        }        AC.build();        /*         * 将模板串建立AC自动机之后枚举矩形中所有的串就可以了         */        for(int i = 0; i < R; i++)        {            AC.find(i, 0, 1); AC.find(i, 0, 2); AC.find(i, 0, 3);            //左边起点,方向为右上,右,右下的字符串            AC.find(i, C - 1, 5); AC.find(i, C - 1, 6); AC.find(i, C - 1, 7);            //右边起点,方向为左上,左,左下的字符串        }        for(int i = 0; i < C; i++)        {            AC.find(0, i, 3); AC.find(0, i, 4); AC.find(0, i, 5);            //上边为起点,方向右下,下,左下            AC.find(R - 1, i, 7); AC.find(R - 1, i, 0); AC.find(R - 1, i, 1);            //下边为起点,方向左上,上,右上        }        for(int i = 0; i < W; i++)            printf("%d %d %c\n", ans[i].x, ans[i].y, ans[i].dir + 'A');         if(t) printf("\n");    }    return 0;}


0 0