POJ 1204 和SPOJ WPUZZLES一样..换了一下输入输出格式而已..
题目大意:
就是现在有一个游戏,给你一个L*C的字符块,只包含大写英文字母,现在你要在这个块中找到给出的所有的英语单词的位置和摆放方向。
其中要找的单词在块中只出现一次,(实际上多个要找的块不会重合,这个游戏就是这样...)
对于每个要找的字符串,输出其在块中起始位置的坐标和方向,方向只有8种,并且单词摆放不会拐弯..就是一条线摆放
大致思路:
其实就是个简单的模板题...首先将所有要找的字符串建立AC自动机,标号其结尾点,然后枚举矩阵的所有串,当然起点和重点都是边界,实际上要枚举的串并不多,找到串的时候利用串的长度和方向就可以很快算出起点位置,最后输出就可以了...
代码如下:
Result : Accepted Memory : 113664 KB Time : 320 ms
/*
* Author: Gatevin
* Created Time: 2014/11/26 15:30:39
* File Name: Kagome.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
int t;
int R, C, W;
char m[1001][1001];
char s[1001];
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
struct Ans
{
int x, y, dir;
};
Ans ans[1001];
int len[1001];
int next[1000001][26], fail[1000001], end[1000001];
struct Trie
{
int L, root;
int newnode()
{
for(int i = 0; i < 26; i++)
next[L][i] = -1;
end[L++] = -1;//end[i] = -1表示点i不是字符串结尾点
return L - 1;
}
void init()
{
L = 0;
root = newnode();
return;
}
void insert(char* in, int id)
{
int now = root;
for(; *in; in++)
{
if(next[now][*in - 'A'] == -1)
next[now][*in - 'A'] = newnode();
now = next[now][*in - 'A'];
}
end[now] = id;
return;
}
void build()
{
fail[root] = root;
queue <int> Q;
Q.push(root);
while(!Q.empty())
{
int now = Q.front();
Q.pop();
for(int i = 0; i < 26; i++)
if(next[now][i] == -1)
next[now][i] = now == root ? root : next[fail[now]][i];
else
{
fail[next[now][i]] = now == root ? root : next[fail[now]][i];
Q.push(next[now][i]);
}
}
return;
}
void find(int x, int y, int dir)
{
int now = root;
while(x >= 0 && y >= 0 && x < R && y < C)
{
now = next[now][m[x][y] - 'A'];
/*
* 由于是字符块游戏,不会出现两块有重叠部分出现的情况
* 所以这里可以不用while(tmp != root) tmp = fail[tmp];这一段
*/
if(end[now] >= 0)//找到字符串了
{
ans[end[now]].x = x - (len[end[now]] - 1)*dx[dir];//计算起点位置
ans[end[now]].y = y - (len[end[now]] - 1)*dy[dir];
ans[end[now]].dir = dir;
}
x += dx[dir];
y += dy[dir];
}
return;
}
};
Trie AC;
int main()
{
scanf("%d", &t);
while(t--)
{
AC.init();
scanf("%d %d %d", &R, &C, &W);
for(int i = 0; i < R; i++)
scanf("%s", m[i]);
for(int i = 0; i < W; i++)
{
scanf("%s", s);
AC.insert(s, i);
len[i] = strlen(s);
}
AC.build();
/*
* 将模板串建立AC自动机之后枚举矩形中所有的串就可以了
*/
for(int i = 0; i < R; i++)
{
AC.find(i, 0, 1); AC.find(i, 0, 2); AC.find(i, 0, 3);
//左边起点,方向为右上,右,右下的字符串
AC.find(i, C - 1, 5); AC.find(i, C - 1, 6); AC.find(i, C - 1, 7);
//右边起点,方向为左上,左,左下的字符串
}
for(int i = 0; i < C; i++)
{
AC.find(0, i, 3); AC.find(0, i, 4); AC.find(0, i, 5);
//上边为起点,方向右下,下,左下
AC.find(R - 1, i, 7); AC.find(R - 1, i, 0); AC.find(R - 1, i, 1);
//下边为起点,方向左上,上,右上
}
for(int i = 0; i < W; i++)
printf("%d %d %c\n", ans[i].x, ans[i].y, ans[i].dir + 'A');
if(t) printf("\n");
}
return 0;
}