搜索入门练习题9 LETTERS 题解

题目出处:《信息学奥赛一本通》第五章上机练习1 或者 POJ1154

题目描述

给出一个 \(R\times S\) 的大写字母矩阵,一开始你所处的位置在左上角,你可以向上下左右四个方向移动,并且不能移到曾经经过的字母(比如,你之前走到过一个'A'上,那么你以后就不能再走到'A'上了)。问最多可以经过几个字母。

输入格式

第一行,输入字母矩阵行数 \(R\) 和列数 \(S\)\(1 \le R,S \le 20\)
接着输入 \(R\) 行,每行为一个包含 \(S\) 个字母的字符串。用于表示 \(R \times 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;
}

猜你喜欢

转载自www.cnblogs.com/zifeiynoip/p/11450727.html