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; }