PKU 1204 Word Puzzles(AC自动机)
题目大意;原题链接
给定一个字符串矩阵和待查找的单词,可以朝8个不同的方向查找,输出待查找单词第一个字母在矩阵中出现的位置和该单词被查到的方向.
A~H代表8个不同的方向,A代表正北方向,其他依次以45度角的方向顺时针增加.
解题思路:
解法一:Trie树暴搜
因为不查询重复单词,所以dfs(int u,int i,int j,int k)函数中当已经查询到单词时,val[u]可以置零做标记.
#include<cstdio>
#include<cstring>
#define maxn 200010
using namespace std;
bool vis[];
int n,m,w,x,y,sz=;//sz得为全局变量
char str[][],word[];
int val[maxn],out[][];
int dir[][]={-,,-,,,,,,,,,-,,-,-,-};//顺时针
struct Trie
{
int next[];
}trie[maxn]; void insert(char *s,int k)
{
int u=,len=strlen(s);
for(int i=;i<len;i++){
int id=s[i]-'A';
if(!trie[u].next[id])
trie[u].next[id]=sz++;
u=trie[u].next[id];
}
val[u]=k;//u为结点编号,k为单词编号
}
void dfs(int u,int i,int j,int k)//k记录方向
{
if(u==||i<||i>=n||j<||j>=m) return;//该语句之前放在if(val[u])条件之后,WA
if(val[u]){
out[val[u]][]=x;
out[val[u]][]=y;
out[val[u]][]=k;
val[u]=;//做标记,因为不查询重复单词
}
int id=str[i+dir[k][]][j+dir[k][]]-'A';
dfs(trie[u].next[id],i+dir[k][],j+dir[k][],k);//必须得朝同一方向搜索
} int main()
{
scanf("%d%d%d",&n,&m,&w);
for(int i=;i<n;i++)
scanf("%s",str[i]);
for(int i=;i<=w;i++){
scanf("%s",word);
insert(word,i);
vis[word[]-'A']=;
}
for(int i=;i<n;i++){
for(int j=;j<m;j++){
if(vis[str[i][j]-'A']){
for(int k=;k<;k++){
x=i,y=j;//记录下最初的位置,从Trie树根开始向下搜索
dfs(trie[].next[str[i][j]-'A'],i,j,k);
}
}
}
}
for(int i=;i<=w;i++)
printf("%d %d %c\n",out[i][],out[i][],out[i][]+'A');
return ;
}
解法二:AC自动机
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
char str[][],word[];
int n,m,w;
int dir[][]={-,,-,,,,,,,,,-,,-,-,-};//顺时针
char ch[]="ABCDEFGH";
int pos[][];
struct TrieNode{
int id;//记录第几个字符串
TrieNode *next[],*fail;
TrieNode(){
id=,fail=;
memset(next,,sizeof(next));
}
}*root; void InsertNode(char *s,int id)
{
int len=strlen(s)-;
TrieNode *p=root;
while(len>=){//这里将s数组倒着插入字典树,方便匹配时记录匹配的终点即原串的起始点
if(!p->next[s[len]-'A'])
p->next[s[len]-'A']=new TrieNode;
p=p->next[s[len--]-'A'];
}
p->id=id;//id记录单词编号
}
void Build_AC()
{
TrieNode *p,*next;
queue<TrieNode* > que;
que.push(root);
while (!que.empty()){
p=que.front();
que.pop();
for(int i=;i<;i++){
if(p->next[i]){
if(p==root) p->next[i]->fail=root;
else{
TrieNode *temp=p->fail;
while(temp){
if(temp->next[i]){//temp始终代表next[i]的爸爸,有next[i]这个儿子
p->next[i]->fail=temp->next[i];
break;//寻找最长后缀
}
temp=temp->fail;
}
if(!temp) p->next[i]->fail=root;
}
que.push(p->next[i]);
}
}
}
}
void Query(int x,int y,int d,int di)
{
TrieNode *p=root,*next;
while(x>=&&y>=&&x<n&&y<m){
while(p&&!p->next[str[x][y]-'A']) p=p->fail;
if(!p) p=root;
else p=p->next[str[x][y]-'A'];
next=p;
while(next!=root){
if(next->id){//记录原串被匹配的起始点
int k=next->id;
if(pos[k][]>x||(pos[k][]==x&&pos[k][]>y)){
pos[k][]=x;
pos[k][]=y;
pos[k][]=di;//记录单词整体朝向
}
}
next=next->fail;
}
x+=dir[d][];
y+=dir[d][];
}
}
void Free(TrieNode *p)
{
for(int i=;i<;i++){
if(p->next[i])
Free(p->next[i]);
}
delete p;
} int main(){
scanf("%d%d%d",&n,&m,&w);
root=new TrieNode;
for(int i=;i<n;i++)
scanf("%s",str[i]);
for(int i=;i<=w;i++){
scanf("%s",&word);
InsertNode(word,i);
pos[i][]=pos[i][]=inf;
}
Build_AC();
for(int i=;i<m;i++){
Query(,i,,),Query(n-,i,,);
Query(,i,,),Query(n-,i,,);
Query(,i,,),Query(n-,i,,);
}//从矩阵上下左右四条边枚举8个方向
for(int i=;i<n;i++){
Query(i,,,),Query(i,m-,,);
Query(i,,,),Query(i,m-,,);
Query(i,,,),Query(i,m-,,);
}
for(int i=;i<=w;i++)
printf("%d %d %c\n",pos[i][],pos[i][],ch[pos[i][]]);
Free(root);
}
后缀数组倍增解法过一段时间补上
PKU 1204 Word Puzzles(AC自动机)的更多相关文章
- [poj] 1204 Word Puzzles || AC自动机
原题 给个X*Y的字符串矩阵,W个询问,对每个询问输出这个串出现的位置及方向,共有8个方向,顺时针开始分别用A~H表示 AC自动机的板子题. 对于待匹配串建一个自动机,然后从矩阵的四周分别沿八个方向跑 ...
- pku1204 Word Puzzles AC自动机 二维字符串矩阵8个方向找模式串的起点坐标以及方向 挺好的!
/** 题目:pku1204 Word Puzzles 链接:http://poj.org/problem?id=1204 题意:给定一个L C(C <= 1000, L <= 1000) ...
- 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 ...
- POJ 题目1204 Word Puzzles(AC自己主动机,多个方向查询)
Word Puzzles Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 10244 Accepted: 3864 S ...
- POJ 1204 Word Puzzles(AC自动机)
这题的数据卡在,如下: 5 5 3 ABCDE FGHIJ KLMNO PQRST UVWXY PQR RS RST puzzle中间的行中可以包含要查询的多个单词.这个问题很好解决,SearchDf ...
- poj 1204 Word Puzzles(字典树)
题目链接:http://poj.org/problem?id=1204 思路分析:由于题目数据较弱,使用暴力搜索:对于所有查找的单词建立一棵字典树,在图中的每个坐标,往8个方向搜索查找即可: 需要注意 ...
- 【POJ】1204 Word Puzzles
这道题目各种wa.首先是错了一个坐标,居然没测出来.然后是剪枝错误.搜索pen时就返回,可能还存在串pen*. #include <cstdio> #include <cstring ...
随机推荐
- RabbitMQ组成及原理介绍-3
rabbitmq作为成熟的企业消息中间件,实现了应用程序间接口调用的解耦,提高系统的吞吐量. 1.RabbitMQ组成 是由 LShift 提供的一个 Advanced Message Queuing ...
- Mac终端运行java程序
1.编辑源文件HelloWorld.java 2.编译源文件 javac HelloWorld.java 生成HelloWorld.class文件 3.执行java字节码 注意,一定要到源目录下,并且 ...
- 在化学教学中怎么用ChemOffice
在21世纪新课程化学教学中,有很多地方要求化学教师使用计算机和应用程序处理各类化学信息,比如课堂教学.撰写教学论文.制作多媒体课件等,这样可以有效增强教学效果.作为化学教师,在新课程的化学教学中掌握一 ...
- iOS开发之-- textview 光标起始位置偏移
使用textview的时候,会发生光标偏移的情况,其实是因为iOS7里导航栏,状态栏等有个边缘延伸的效果在. 把边缘延伸关掉就好了.代码如下 //取消iOS7的边缘延伸效果(例如导航栏,状态栏等等) ...
- 使用Audio API设计绚丽的HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...
- handlebears使用
Handlebars 文档笔记: http://www.ghostchina.com/handlebars-wen-dang-bi-ji/ Handlebars模板引擎中的each嵌套及源码浅读: h ...
- c#基础 第四讲
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- style、currentStyle、getComputedStyle(不同浏览器获取css样式)区别介绍
style.currentStyle.getComputedStyle区别介绍 样式表有三种方式 内嵌样式(inline Style) :是写在Tag里面的,内嵌样式只对所有的Tag有效. 内部样 ...
- Servlet------>jsp自定义标签SimpleTag(jsp2.0以后的方法,1-5已经淘汰了)
自定义标签能做什么: 1.移除java代码 2.控制jsp页面某一部分是否执行 3.控制整个jsp是否执行 3.jsp内容重复输出 4.修改jsp内容输出 位置: TagDemo1.java pack ...
- 具备双向通行能力的架构对于移动APP属于刚性需求。 WebSocket连接 注册信令
双向通信使用指南_用户指南(开放 API)_API 网关-阿里云 https://help.aliyun.com/document_detail/66031.html 流程描述 (1) 客户端在启动的 ...