题目描述
注意:本题允许使用C/C++/Java/python进行解答,其他编程语言提交均视作无效处理。
字符迷阵是一种经典的智力游戏。玩家需要在给定的矩形的字符迷阵中寻找特定的单词。
在这题的规则中,单词是如下规定的:
1. 在字符迷阵中选取一个字符作为单词的开头;
2. 选取右方、下方、或右下45度方向作为单词的延伸方向;
3. 以开头的字符,以选定的延伸方向,把连续得到的若干字符拼接在一起,则称为一个单词。
以图1为例,如果要在其中寻找单词"WORD",则绿色框所标示的都是合法的方案,而红色框所标示的都是不合法的方案。
现在的问题是,给出一个字符迷阵,及一个要寻找的单词,问能在字符迷阵中找到多少个该单词的合法方案。注意合法方案是可以重叠的,如图1所示的字符迷阵,其中单词"WORD"的合法方案有4种。
输入描述:
输入的第一行为一个正整数T,表示测试数据组数。 接下来有T组数据。每组数据的第一行包括两个整数m和n,表示字符迷阵的行数和列数。接下来有m行,每一行为一个长度为n的字符串,按顺序表示每一行之中的字符。再接下来还有一行包括一个字符串,表示要寻找的单词。 数据范围: 对于所有数据,都满足1<=T<=9,且输入的所有位于字符迷阵和单词中的字符都为大写字母。要寻找的单词最短为2个字符,最长为9个字符。字符迷阵和行列数,最小为1,最多为99。 对于其中50%的数据文件,字符迷阵的行列数更限制为最多为20。
输出描述:
对于每一组数据,输出一行,包含一个整数,为在给定的字符迷阵中找到给定的单词的合法方案数。
示例1
输入
复制
3 10 10 AAAAAADROW WORDBBBBBB OCCCWCCCCC RFFFFOFFFF DHHHHHRHHH ZWZVVVVDID ZOZVXXDKIR ZRZVXRXKIO ZDZVOXXKIW ZZZWXXXKIK WORD 3 3 AAA AAA AAA AA 5 8 WORDSWOR ORDSWORD RDSWORDS DSWORDSW SWORDSWO SWORD
输出
复制
4 16 5
题解:这道题完全可以直接暴力,但是我还是用这道题测一下kmp的模板,所以这道题我是用kmp写的
#include <bits/stdc++.h>
using namespace std;
char s[109];
vector<int> prefix_table(vector<char> pattern){
int n = pattern.size();
vector<int> prefix(pattern.size());
prefix[0] = 0;
int len = 0;
int i = 1;
while (i < n){
if(pattern[i] == pattern[len]){
len++;
prefix[i] = len;
i++;
} else {
if(len > 0){
len = prefix[len - 1];
} else {
prefix[i] = len;
i++;
}
}
}
return prefix;
}
vector<int> move(vector<char> pattern){
vector<int> prefix = prefix_table(pattern);
int n = prefix.size();
for (int i = n - 1; i >= 0; i--){
prefix[i] = prefix[i - 1];
}
prefix[0] = -1;
return prefix;
}
int kmp_search(vector<char>& text, vector<char>& pattern){
int ans = 0;
vector<int> prefix = move(pattern);
int m = text.size();
int n = pattern.size();
int i = 0, j = 0;
while(i < m){
if(j == n - 1 && text[i] == pattern[j]){
ans++;
j = prefix[j];
}
if(pattern[j] == text[i]){
i++;
j++;
} else {
j = prefix[j];
if(j == -1){
j++;
i++;
}
}
}
return ans;
}
int main(){
int tt;
cin >> tt;
while(tt--){
int n, m, sum = 0;
scanf("%d %d", &n, &m);
vector<vector<char>> dict(n);
vector<char> pattern;
dict.clear();
pattern.clear();
for (int i = 0; i < n; i++){
vector<char> c;
c.clear();
scanf("%s", s);
for (int j = 0; j < m; j++){
c.push_back(s[j]);
}
dict.push_back(c);
}
scanf("%s", s);
for (int i = 0; i < strlen(s); i++){
pattern.push_back(s[i]);
}
for (int i = 0; i < n; i++){
vector<char> ss = dict[i];
sum += kmp_search(ss, pattern);
}
for (int i = 0; i < m; i++){
vector<char> ss;
ss.clear();
for (int j = 0; j < n; j++){
ss.push_back(dict[j][i]);
}
sum += kmp_search(ss, pattern);
}
for (int i = 1; i < n; i++){
vector<char> ss;
ss.clear();
int x = i, y = 0;
while(x < n && y < m){
ss.push_back(dict[x][y]);
x++;y++;
}
sum += kmp_search(ss, pattern);
}
for (int i = 0; i < m; i++){
vector<char> ss;
ss.clear();
int x = 0, y = i;
while(x < n && y < m){
ss.push_back(dict[x][y]);
x++; y++;
}
sum += kmp_search(ss, pattern);
}
cout << sum << "\n";
}
return 0;
}
当然下面也给出一个暴力的方法:
#include <bits/stdc++.h>
using namespace std;
string ss[110];
int main(){
auto get1 = [&](int foo, int bar, int n, int m, int len){
int k = 0;
string s = "";
while (k < len && bar + k < m){
s += ss[foo][bar + k];
k++;
}
return s;
};
auto get2 = [&](int foo, int bar, int n, int m, int len){
int k = 0;
string s = "";
while (k < len && foo + k < n){
s += ss[foo + k][bar];
k++;
}
return s;
};
auto get3 = [&](int foo, int bar, int n, int m, int len){
int k = 0;
string s = "";
while (k < len && bar + k < m && foo + k < n){
s += ss[foo + k][bar + k];
k++;
}
return s;
};
int tt;
cin >> tt;
while(tt--){
int n, m, ans = 0;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++){
cin >> ss[i];
}
string s;
cin >> s;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
string g[3];
g[0] = get1(i, j, n, m, s.length());
g[1] = get2(i, j, n, m, s.length());
g[2] = get3(i, j, n, m, s.length());
if(s == g[0]) ans++;
if(s == g[1]) ans++;
if(s == g[2]) ans++;
}
}
cout << ans << "\n";
}
return 0;
}