题目出处:《信息学奥赛一本通》第五章上机练习1 或者 POJ1154
题目描述
给出一个 (R imes S) 的大写字母矩阵,一开始你所处的位置在左上角,你可以向上下左右四个方向移动,并且不能移到曾经经过的字母(比如,你之前走到过一个'A'上,那么你以后就不能再走到'A'上了)。问最多可以经过几个字母。
输入格式
第一行,输入字母矩阵行数 (R) 和列数 (S) , (1 le R,S le 20) 。
接着输入 (R) 行,每行为一个包含 (S) 个字母的字符串。用于表示 (R imes S) 的字母矩阵。
输出格式
输出一个数字,用于表示最多能走过的不同的字母的个数。
样例输入
3 6
HFDFFB
AJHGDH
DGAGEH
样例输出
6
题目分析
我们设行数为 (R) ,列数为 (S) ,用于保存字符的二维数组为 ch[][]
。
我们开一个布尔数组 bool vis[26]
,其中 vis[0]
用于表示字母 'A' 是否走到过,vis[1]
用于表示字母 'B' 是否走到过,……, vis[25]
用于表示字母 'Z' 是否走到过。
同时我们开一个搜索函数 dfs(int x, int y, int step)
,用于表示 “我当前在二维数组中的第 (x) 行第 (y) 列,并且我已经走了 (step) 步了” 这样一个状态。然后我遍历 ((x,y)) 的上下左右4个点 ((xx,yy)) ,如果 ((xx,yy)) 能走到并且 ch[xx][yy]
上的那个字符我之前没有走到过,那么我可以递归的执行 dfs(xx, yy, step+1)
。
对于 step
,如果 step
比我当前记录的最大步数要大,则更新最大步数为 step
(在下面的程序中我是用 ans
来表示最大步数的)。实现代码如下:
#include <bits/stdc++.h>
using namespace std;
int R, S, ans; // R,S分别表示行数和列数,ans表示最多经过字母数
int dir[4][2] = { -1, 0, 1, 0, 0, -1, 0, 1 }; // dir数组用于表示上下左右4个方向
char ch[22][22]; // ch数组用于表示我们的二位地图
bool vis[26]; // vis数组用于记录26个字母是否有走过,其中'A'对应vis[0],'B'对应vis[1],…
// in_map函数用于判断第x行第y列的元素是否超过地图边界
bool in_map(int x, int y) {
return x >= 0 && x < R && y >= 0 && y < S;
}
// dfs函数用于搜索,它表示当前在第x行第y列,已经走了step步
void dfs(int x, int y, int step) {
vis[ ch[x][y] - 'A' ] = true; // 首先将当且(x,y)这个点对应的字母的vis值标记为true
if (step > ans) ans = step; // 如果step比ans大,更新ans为step
for (int i = 0; i < 4; i ++) { // 遍历四个方向
int xx = x + dir[i][0];
int yy = y + dir[i][1]; // (xx,yy)就是新探索到的点
if (in_map(xx, yy) && !vis[ ch[xx][yy] - 'A' ]) { // 如果可以走,尝试性地走
dfs(xx, yy, step+1);
}
}
vis[ ch[x][y] - 'A' ] = false; // 因为搜索是尝试放,所以推出本次搜索记得将vis值标记回false
}
int main() {
cin >> R >> S;
for (int i = 0; i < R; i ++) cin >> ch[i];
dfs(0, 0, 1);
cout << ans << endl;
return 0;
}