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 ...
随机推荐
- 学习:erlang的term反序列化,string转换为term
一. string_to_term(String) -> case erl_scan:string(String++".") of {ok, Tokens ...
- 【NLP】course
http://52opencourse.com/235/%E6%96%AF%E5%9D%A6%E7%A6%8F%E5%A4%A7%E5%AD%A6%E8%87%AA%E7%84%B6%E8%AF%AD ...
- hdu 1813(IDA*)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1813 思路:首先bfs预处理出‘0’到边界点最短距离,然后构造 h() 为所’0‘点逃离迷宫的最少步数 ...
- mac 10.9 dock在多屏幕间移动
想要在哪个屏幕使用dock,就在这个屏幕把鼠标移动到最底部即可.神奇吧?太意外了...居然被我发现了...
- JSON-Server 安装
在后台还没给接口之前,使用JSON-Server搭建一台JSON服务器,将接口要返回的数据放在json文件里面.然后请求这些数据,这样我们可以先做一些东西,等后台接口好了之后直接替换就可以了,不必一直 ...
- 【BZOJ2424】[HAOI2010]订货 最小费用流
[BZOJ2424][HAOI2010]订货 Description 某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定 ...
- jQuery照片墙相册
效果体验:http://keleyi.com/keleyi/phtml/jqtexiao/30.htm 本特效支持jquery的版本为1.4.3,暂时不支持1.9以上jquery版本. 代码: < ...
- xpath scrapy shell
w from scrapy.spider import Spider from scrapy.crawler import CrawlerProcess import pymysql conn = p ...
- 重装系统后Myeclipse遇到的项目配置问题--一个菜鸟的经历!
电脑不知道为什么流量突然变大了. 一查svchost.exe后台下载老多系统.某某安全卫士根本么用,运维说用某企鹅管家. 结果一个鸟样.. 之前是系统是32位的win7 4G内存用不完.又打算升级内 ...
- 一个误区(关于javascript的字符串拼接)
前段时间听说了一个问题,说是,javascript中使用+=来拼接字符串会比使用Array的join方法慢几十倍以上,今天在工作间歇,就写了个例 子验证了一下,结果确完全相反,使用+=比join要快( ...