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 ...
随机推荐
- 使用ANT编译项目报错 com.sun.image.codec.jpeg does not exist 解决方法
项目开发中在对图片进行裁切处理的时候,有时候是会使用到 com.sun 包下的类时. 假设项目使用ant编译,会出现错误 com.sun.image.codec.jpeg does not exist ...
- Python+PyQt5:停靠组件QDockWidget的实现
QMainWindow主窗体中放置停靠组件QDockWidget的实现流程: 第一步:创建QMainWindow窗体,这是承载QDockWidget的主体 第二步:创建QDockWidget组件实例, ...
- winform 递归循环阻止机构
private void GetTree() { DataTable dt = new DataTable(); var sql = @" select OUID,ParentOUID,OU ...
- 概览C++之const
1.C语言中const与 C++中的const void main() { const int a = 10; int *p = (int*)&a; *p = 20; printf(" ...
- CodeForces 558C Amr and Chemistry (位运算,数论,规律,枚举)
Codeforces 558C 题意:给n个数字,对每一个数字能够进行两种操作:num*2与num/2(向下取整),求:让n个数相等最少须要操作多少次. 分析: 计算每一个数的二进制公共前缀. 枚举法 ...
- Spring_day01--Spring的bean管理(xml方式)_属性注入介绍
Spring的bean管理(xml方式) Bean实例化的方式 1 在spring里面通过配置文件 创建对象 2 bean实例化(创建对象)三种方式实现 第一种 使用类的无参数构造创建(重点) Use ...
- C语言switch语句
C语言虽然没有限制 if else 能够处理的分支数量,但当分支过多时,用 if else 处理会不太方便,而且容易出现 if else 配对出错的情况.例如,输入一个整数,输出该整数对应的星期几的英 ...
- My97DatePicker设置,包括隐藏 清空,设置最大日期等 转载
My97DatePicker是一款非常灵活好用的日期控件.使用非常简单. 1.下载My97DatePicker组件包 2.在页面中引入该组件js文件: <script type=&quo ...
- 【POJ3565】ANTS KM算法
[POJ3565]ANTS 题意:平面上有2*n个点,N白N黑.为每个白点找一个黑点与之连边,最后所有边不交叉.求一种方案. 题解:KM算法真是一个神奇的算法,虽然感觉KM能做的题用费用流都能做~ 本 ...
- Caused by: java.lang.ClassNotFoundException[android的终极解决错误]
from:http://blog.csdn.net/changemyself/article/details/7861525 08-13 18:29:22.924: E/AndroidRuntime( ...