题目大意;原题链接

给定一个字符串矩阵和待查找的单词,可以朝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自动机)的更多相关文章

  1. [poj] 1204 Word Puzzles || AC自动机

    原题 给个X*Y的字符串矩阵,W个询问,对每个询问输出这个串出现的位置及方向,共有8个方向,顺时针开始分别用A~H表示 AC自动机的板子题. 对于待匹配串建一个自动机,然后从矩阵的四周分别沿八个方向跑 ...

  2. pku1204 Word Puzzles AC自动机 二维字符串矩阵8个方向找模式串的起点坐标以及方向 挺好的!

    /** 题目:pku1204 Word Puzzles 链接:http://poj.org/problem?id=1204 题意:给定一个L C(C <= 1000, L <= 1000) ...

  3. POJ 1204 Word Puzzles | AC 自动鸡

    题目: 给一个字母矩阵和几个模式串,矩阵中的字符串可以有8个方向 输出每个模式串开头在矩阵中出现的坐标和这个串的方向 题解: 我们可以把模式串搞成AC自动机,然后枚举矩阵最外围一层的每个字母,向八个方 ...

  4. 【 POJ - 1204 Word Puzzles】(Trie+爆搜|AC自动机)

    Word Puzzles Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 10782 Accepted: 4076 Special ...

  5. [POJ 1204]Word Puzzles(Trie树暴搜&amp;AC自己主动机)

    Description Word puzzles are usually simple and very entertaining for all ages. They are so entertai ...

  6. POJ 题目1204 Word Puzzles(AC自己主动机,多个方向查询)

    Word Puzzles Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10244   Accepted: 3864   S ...

  7. POJ 1204 Word Puzzles(AC自动机)

    这题的数据卡在,如下: 5 5 3 ABCDE FGHIJ KLMNO PQRST UVWXY PQR RS RST puzzle中间的行中可以包含要查询的多个单词.这个问题很好解决,SearchDf ...

  8. poj 1204 Word Puzzles(字典树)

    题目链接:http://poj.org/problem?id=1204 思路分析:由于题目数据较弱,使用暴力搜索:对于所有查找的单词建立一棵字典树,在图中的每个坐标,往8个方向搜索查找即可: 需要注意 ...

  9. 【POJ】1204 Word Puzzles

    这道题目各种wa.首先是错了一个坐标,居然没测出来.然后是剪枝错误.搜索pen时就返回,可能还存在串pen*. #include <cstdio> #include <cstring ...

随机推荐

  1. hdu 1233 还是畅通project

    本题链接:点击打开链接 本题大意: 有n个村庄,n*(n-1)/2条路,输入每条路所连接是哪两个村庄及长度,求使全部村庄均连通(并不是都两两连通) 所铺公路的最短路程. 解题思路: 使用并查集基础及K ...

  2. linux系统命令记录

    系统 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/cpuinfo # 查看CPU信息 # ho ...

  3. Mac终端运行java程序

    1.编辑源文件HelloWorld.java 2.编译源文件 javac HelloWorld.java 生成HelloWorld.class文件 3.执行java字节码 注意,一定要到源目录下,并且 ...

  4. STL容器:list双向链表学习

    list是一个双向列表容器,完成了标准C++数据结构中链表的所有功能; list与vector和deque类似,只不过其中的对象提供了对元素的随机访问. STL以双向链表的方式实现list,访问需要从 ...

  5. LINQ to SQL语句(2)Count/Sum/Min/Max/Avg操作符

    使用场景 类似于SQL中的聚合函数,用于统计数据,不延迟.如返回序列中的元素数量.求和.最小值.最大值.求平均值. Count 说明:用于返回集合中元素的个数,返回Int类型,生成SQL语句为SELE ...

  6. Linux环境下Apache配置多个虚拟主机挂载多站点同时运行

    博客地址: http://blog.csdn.net/ClydeKuo/article/details/69569474 这篇博客讲的很详细,很详细.

  7. swift - UIView 设置背景色和背景图片

    代码如下: let page = UIView() page.frame = self.view.bounds //直接设置颜色 page.backgroundColor = UIColor.gree ...

  8. 【RF库测试】对出错的处理

    1.出错后继续执行:Run Keyword And Continue On Failure 2.获取关键字执行结果后继续执行:Run Keyword And Ignore Error 有时候,我们需要 ...

  9. Unreal开发HTC Vive程序,开启VR编辑模式

    新建项目模板有个VirtualReality 调试的时候,Play按钮下拉有个VR Preview 打开VR模式,在我现在用的4.15.0版本,VR编辑模式还是预览功能,可以在“编辑器偏好设置”-“试 ...

  10. 应用开发之WinForm开发

    本章简言 上一章笔者介绍了关于WinForm环境.这一章笔者将继续讲WinForm.只不过更加的面向开发了.事实就是在学习工具箱里面的控件.对于WinForm开发来讲,企业对他的要求并没有那么高.但是 ...