AC自动机 - Word Puzzles - POJ - 1204

AC自动机 - Word Puzzles - POJ - 1204

题意:

给 定 一 个 l × c 的 字 符 矩 阵 , 以 及 w 个 字 符 串 , 需 要 找 出 w 个 字 符 串 在 矩 阵 中 出 现 的 位 置 。 输 出 字 符 串 第 一 个 字 符 的 坐 标 以 及 字 符 串 的 “ 方 向 ” ( 共 8 个 方 向 ) , 由 8 个 字 母 A − H 表 示 8 个 方 向 , 从 A 开 始 代 表 北 , 顺 时 针 依 次 为 B , C , D , . . . , H 。 给定一个l×c的字符矩阵,以及w个字符串,需要找出w个字符串在矩阵中出现的位置。\\输出字符串第一个字符的坐标以及字符串的“方向”(共8个方向),\\由8个字母A-H表示8个方向,从A开始代表北,顺时针依次为B,C,D,...,H。 l×cww(8)8AH8AB,C,D,...,H

Sample Input:
20 20 10
QWSPILAATIRAGRAMYKEI
AGTRCLQAXLPOIJLFVBUQ
TQTKAZXVMRWALEMAPKCW
LIEACNKAZXKPOTPIZCEO
FGKLSTCBTROPICALBLBC
JEWHJEEWSMLPOEKORORA
LUPQWRNJOAAGJKMUSJAE
KRQEIOLOAOQPRTVILCBZ
QOPUCAJSPPOUTMTSLPSF
LPOUYTRFGMMLKIUISXSW
WAHCPOIYTGAKLMNAHBVA
EIAKHPLBGSMCLOGNGJML
LDTIKENVCSWQAZUAOEAL
HOPLPGEJKMNUTIIORMNC
LOIUFTGSQACAXMOPBEIO
QOASDHOPEPNBUYUYOBXB
IONIAELOJHSWASMOUTRK
HPOIYTJPLNAQWDRIBITG
LPOINUYMRTEMPTMLMNBO
PAFCOPLHAVAIANALBPFS
MARGARITA
ALEMA
BARBECUE
TROPICAL
SUPREMA
LOUISIANA
CHEESEHAM
EUROPA
HAVAIANA
CAMPONESA

Sample Output:
0 15 G
2 11 C
7 18 A
4 8 C
16 13 B
4 15 E
10 3 D
5 1 E
19 7 C
11 11 H

数据范围:
l , c , w ∈ [ 1 , 1000 ] 。 T i m e   l i m i t : 5000 m s   M e m o r y   l i m i t : 65536 k B l,c,w∈[1,1000]。\\Time \ limit:5000 ms\ Memory \ limit:65536 kB l,c,w[1,1000]Time limit:5000ms Memory limit:65536kB

题解:

对 k 个 字 符 串 建 T r i e 图 , 接 着 对 每 个 字 符 暴 力 搜 索 八 个 方 向 在 图 上 匹 配 , 记 下 匹 配 成 功 的 坐 标 和 方 向 即 可 。 对k个字符串建Trie图,接着对每个字符暴力搜索八个方向在图上匹配,记下匹配成功的坐标和方向即可。 kTrie

具体落实:

① 、 建 T r i e 图 , 插 入 的 过 程 中 给 每 个 结 尾 字 符 打 标 记 , 每 个 单 词 的 i d 记 为 其 输 入 的 序 号 , 方 便 匹 配 成 功 的 判 断 。 ② 、 爆 搜 的 过 程 可 以 从 矩 阵 四 条 边 上 的 点 进 入 , 来 减 少 重 复 搜 索 , 同 时 也 能 避 免 遗 漏 , 保 证 每 种 可 能 性 均 被 搜 到 。 ①、建Trie图,插入的过程中给每个结尾字符打标记,每个单词的id记为其输入的序号,方便匹配成功的判断。\\②、爆搜的过程可以从矩阵四条边上的点进入,来减少重复搜索,同时也能避免遗漏,保证每种可能性均被搜到。 Trieid便


代码:

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
const int N=1010;
using namespace std;

int l, c, idx = 1, w,ans[N][3], len[N];
char s[N][N], s2[N],dir[N];

int dx[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
int dy[] = { 0, 1, 1, 1, 0, -1, -1, -1 };

struct node
{
    int tr[30], id, fail;
}e[N * 110];

void Insert(char *str,int x)
{
    int u = 1;
    for (int i = 0;str[i]; i++)
    {
        int t = str[i] - 'A';
        if (!e[u].tr[t])
            e[u].tr[t] = ++idx;
        u = e[u].tr[t];
    }
    e[u].id = x;
}

void build()
{
    for (int i = 0; i < 26; i++)
        e[0].tr[i] = 1;
    queue <int> q;
    q.push(1);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        int fail = e[u].fail;
        for (int i = 0; i < 26; i++)
        {
            int y = e[u].tr[i];
            if (y)
            {
                e[y].fail = e[fail].tr[i];
                q.push(y);
            }
            else
                e[u].tr[i] = e[fail].tr[i];
        }
    }
}

void dfs(int sx, int sy, int d)
{
    int x = sx, y = sy, u = 1;
    while (x >= 1 && x <= l && y >= 1 && y <= c)
    {
        while (u && !e[u].tr[s[x][y] - 'A'])
            u = e[u].fail;
        u = e[u].tr[s[x][y] - 'A'];
        if (e[u].id)
        {
            ans[e[u].id][1] = x - (len[e[u].id] - 1) * dx[d];  ///回到第一个字母
            ans[e[u].id][2] = y - (len[e[u].id] - 1) * dy[d];
            dir[e[u].id] = d;
        }
        x += dx[d];
        y += dy[d];
    }
}

int main()
{
    scanf("%d%d%d", &l, &c, &w);
    for (int i = 1; i <= l; i++)
        scanf("%s", s[i] + 1);
    for (int i = 1; i <= w; i++)
    {
        scanf("%s", s2);
        len[i] = strlen(s2);
        Insert(s2,i);
    }

    build();

    for (int i = 1; i <= l; i++)
        for (int j = 0; j < 8; j++)
            dfs(i, 1, j), dfs(i, c, j);
    for (int i = 1; i <= c; i++)
        for (int j = 0; j < 8; j++)
            dfs(1, i, j), dfs(l, i, j);

    for (int i = 1; i <= w; i++)
        printf("%d %d %c\n", ans[i][1] - 1, ans[i][2] - 1, dir[i] + 'A');

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值