POJ 1204 Word Puzzles(AC自动机)
这题的数据卡在,如下:
5 5 3
ABCDE
FGHIJ
KLMNO
PQRST
UVWXY
PQR
RS
RST
puzzle中间的行中可以包含要查询的多个单词。这个问题很好解决,SearchDfa的时候别return就行了,一直搜到字符串的结尾。
但是这样做也有一个bug,如果数据是这样的:
4 7 5
ABCDEFG
HIJKLMN
OPQRSTU
VWXYZAK
RSTU
STU
TU
JKL
KL
也就是说查询单词里面,大单词包含着小单词,实际上是很难处理的。我的一个设想是遇到所有危险节点的时候,都访问,该节点的所有前缀节点,并记录该前缀的位置信息,也就是要搜索的单词。这个搜索的时候同样不能return,因为小单词后面可能有大单词。
不过也可以搜索所有的点,每个点的8个方向都搜索一下,不过时间开销太大。
对于这题的输入其实很好处理,每一个单词都设置一个唯一的标号,然后构造tire的时候,在每个叶子节点上标记上这个唯一个标号。这样就是唯一的表示,不需要再这个单词的每一个字符上都标志它的标号,因为其他单词来的时候还得改,没用。
代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
const int maxn=1010;
const int LETTERS=26;
int nNodesCount=0;
int str_num=-1,l,c,w;;
struct CNode {
CNode * pChilds[LETTERS];
CNode * pPrev;
bool bBadNode;
int num;
void Init() {
memset(pChilds,0,sizeof(pChilds));
pPrev=NULL;
bool bBadNode=false;
}
};
CNode Tree[maxn*maxn];
char puzzle[maxn][maxn];
char words[maxn][maxn];
int loc[maxn][3];
int d[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
int pd[8]={0,4,6,2,7,1,5,3};
//上下左右 左上 右上 左下 右下
void Insert(CNode * pRoot,char * s,int num)
{
for (int i=0;s[i];i++) {
if (pRoot->pChilds[s[i]-'A']==NULL) {
pRoot->pChilds[s[i]-'A']=Tree+nNodesCount;
nNodesCount++;
}
pRoot=pRoot->pChilds[s[i]-'A'];
}
pRoot->bBadNode=true;
pRoot->num=num;
}
void BuildDfa()
{
for (int i=0;i<LETTERS;i++) {
Tree[0].pChilds[i]=Tree+1;
}
Tree[0].pPrev=NULL;
Tree[1].pPrev=Tree;
deque<CNode *> q;
q.push_back(Tree+1);
while (!q.empty()) {
CNode * pRoot=q.front();
q.pop_front();
for (int i=0;i<LETTERS;i++) {
CNode * p=pRoot->pChilds[i];
if (p) {
CNode * pPrev=pRoot->pPrev;
while (pPrev) {
if (pPrev->pChilds[i]) {
p->pPrev=pPrev->pChilds[i];
if (p->pPrev->bBadNode) {
p->bBadNode=true;
}
break;
}
else {
pPrev=pPrev->pPrev;
}
}
q.push_back(p);
}
}
}
}
void SearchDfa(int x,int y,int dir)
{
CNode * p=Tree+1;
while (x>=0&&x<l&&y>=0&&y<c) {
while (true) {
if (p->pChilds[puzzle[x][y]-'A']) {
p=p->pChilds[puzzle[x][y]-'A'];
if (p->bBadNode) {
int len=strlen(words[p->num]);
loc[p->num][0]=x-(len-1)*d[dir][0];
loc[p->num][1]=y-(len-1)*d[dir][1];
loc[p->num][2]=pd[dir];
}
break;
}
else {
p=p->pPrev;
}
}
x+=d[dir][0];
y+=d[dir][1];
}
}
int main()
{
nNodesCount=2;
scanf("%d%d%d",&l,&c,&w);
for (int i=0;i<l;i++) {
scanf("%s",puzzle[i]);
}
for (int i=0;i<w;i++) {
scanf("%s",words[i]);
Insert(Tree+1,words[i],i);
}
BuildDfa();
for (int i=0;i<l;i++) {
for (int k=0;k<8;k++) {
SearchDfa(i,0,k);
SearchDfa(i,c-1,k);
}
}
for (int j=0;j<c;j++) {
for (int k=0;k<8;k++) {
SearchDfa(0,j,k);
SearchDfa(l-1,j,k);
}
}
for (int i=0;i<w;i++) {
printf("%d %d %c\n",loc[i][0],loc[i][1],loc[i][2]+'A');
}
return 0;
}
/*
5 5 3
ABCDK
EFGHN
IJKLS
MNOPD
QRSTP
4 7 5
ABCDEFG
HIJKLMN
OPQRSTU
VWXYZAK
RSTU
STU
TU
JKL
KL
*/
POJ 1204 Word Puzzles(AC自动机)的更多相关文章
- [poj] 1204 Word Puzzles || AC自动机
原题 给个X*Y的字符串矩阵,W个询问,对每个询问输出这个串出现的位置及方向,共有8个方向,顺时针开始分别用A~H表示 AC自动机的板子题. 对于待匹配串建一个自动机,然后从矩阵的四周分别沿八个方向跑 ...
- PKU 1204 Word Puzzles(AC自动机)
题目大意:原题链接 给定一个字符串矩阵和待查找的单词,可以朝8个不同的方向查找,输出待查找单词第一个字母在矩阵中出现的位置和该单词被查到的方向. A~H代表8个不同的方向,A代表正北方向,其他依次以4 ...
- POJ 1204 Word Puzzles | AC 自动鸡
题目: 给一个字母矩阵和几个模式串,矩阵中的字符串可以有8个方向 输出每个模式串开头在矩阵中出现的坐标和这个串的方向 题解: 我们可以把模式串搞成AC自动机,然后枚举矩阵最外围一层的每个字母,向八个方 ...
- 【 POJ - 1204 Word Puzzles】(Trie+爆搜|AC自动机)
Word Puzzles Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 10782 Accepted: 4076 Special ...
- [POJ 1204]Word Puzzles(Trie树暴搜&AC自己主动机)
Description Word puzzles are usually simple and very entertaining for all ages. They are so entertai ...
- pku1204 Word Puzzles AC自动机 二维字符串矩阵8个方向找模式串的起点坐标以及方向 挺好的!
/** 题目:pku1204 Word Puzzles 链接:http://poj.org/problem?id=1204 题意:给定一个L C(C <= 1000, L <= 1000) ...
- poj 1204 Word Puzzles(字典树)
题目链接:http://poj.org/problem?id=1204 思路分析:由于题目数据较弱,使用暴力搜索:对于所有查找的单词建立一棵字典树,在图中的每个坐标,往8个方向搜索查找即可: 需要注意 ...
- POJ 题目1204 Word Puzzles(AC自己主动机,多个方向查询)
Word Puzzles Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 10244 Accepted: 3864 S ...
- poj 2778 DNA Sequence ac自动机+矩阵快速幂
链接:http://poj.org/problem?id=2778 题意:给定不超过10串,每串长度不超过10的灾难基因:问在之后给定的长度不超过2e9的基因长度中不包含灾难基因的基因有多少中? DN ...
随机推荐
- 二分题 D - Salary Changing codeforce
题意:给出n个人(n是奇数),s钱:s为总的可以付工钱的钱: 每一个工人有一个付工钱的区间,只要在这个区间范围内,随便一个数都可以当作给这个工人付了钱: 老板要付给每个工人钱,并且付钱的中位数要尽可能 ...
- deepin linux 安装之后 引导错误 出现 grub>
deepin 安装之后 引导错误 ,,, 忙了一晚上 终于解决了 太辛苦了 不过明白了grub的工作原理也不亏,,,, 就是 整个过程满满的绝望 (哭 环境说明 华硕顽石4 笔记本 硬盘分区表GPT ...
- 对C#继承、多态的理解
11月3日 阴天 前两天看某位大牛写的程序,对于C#多态有困惑,今天一大早来查阅了不少资料,自认为有了一个基本的认知,记录下来,一扫今天这阴霾的天气 ------------------------- ...
- 网络常识---tracert
当打不开一个网页,可以是用如下命令查看请求的数据走到哪里了 在命令行中输入“tracert ”并在后面加入一个IP地址,可以查询从本机到该IP地址所在的电脑要经过的路由器及其IP地址
- Docker Compose 使用示例
一般步骤 1.定义Dockerfile,方便迁移到任何地方: 2.编写docker-compose.yml文件: 3.运行docker-compose up启动服务 示例 准备工作:提前下载好镜像: ...
- 8.10-DayT3游走(wander)
题目大意 lue.. 题解 先跑一遍tarjan缩点,在新图中加入两个强连通分量之间的边,则此图为一个有向无环图(DAG).则最终答案为1点所在的强连通分量或包括1点的几个强连通分量的点数之和. 如果 ...
- 7_3 分数拆分(UVa10976)<缩小枚举范围>
每一个(k>0)这种形式的分数我们总是可以找到2个正整数x和y(x >= y),使得:现在我们的问题是:给你k,请你写一个程序找出所有的x和y.Input输入含有多组测试数据(不会超过10 ...
- 第二十九篇 玩转数据结构——线段树(Segment Tree)
1.. 线段树引入 线段树也称为区间树 为什么要使用线段树:对于某些问题,我们只关心区间(线段) 经典的线段树问题:区间染色,有一面长度为n的墙,每次选择一段墙进行染色(染色允许覆盖),问 ...
- Redis的安装与用法
Redis的使用方法 ( 命令行安装redis 1 wget http://download.redis.id/releases/redis-5.0.7.tar.gz 2 tar xf redis- ...
- Ubuntu中获取和使用uiautomatorviewer
图省事的办法是直接在网上找个android platform tools的某个版本下载下来 比如这个网站里面的:Android SDK工具——Platform-tools 个人比较倾向于先下载andr ...