题目描述
问题描述
给定一个R行C列的地图,地图的每一个方格可能是’#’, ‘+’, ‘-’, ‘|’, ‘.’, ‘S’, ‘T’七个字符中的一个,分别表示如下意思:
‘#’: 任何时候玩家都不能移动到此方格;
‘+’: 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非’#‘方格移动一格;
‘-’: 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非’#‘方格移动一格;
‘|’: 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非’#‘方格移动一格;
‘.’: 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为’#’,则玩家不能再移动;
‘S’: 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非’#‘方格移动一格;
‘T’: 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非’#'方格移动一格。
此外,玩家不能移动出地图。
请找出满足下面两个性质的方格个数:
1. 玩家可以从初始位置移动到此方格;
2. 玩家不可以从此方格移动到目标位置。
输入格式
输入的第一行包括两个整数R 和C,分别表示地图的行和列数。(1 ≤ R, C ≤ 50)。
接下来的R行每行都包含C个字符。它们表示地图的格子。地图上恰好有一个’S’和一个’T’。
输出格式
如果玩家在初始位置就已经不能到达终点了,就输出“I’m stuck!”(不含双引号)。否则的话,输出满足性质的方格的个数。
样例输入
5 5
–±+
…|#.
…|##
S-±T
####.
样例输出
2
样例说明
如果把满足性质的方格在地图上用’X’标记出来的话,地图如下所示:
–±+
…|#X
…|##
S-±T
####X
解题方案
1. 解题思路
满足性质的方格需要满足两种条件:
- 玩家可以从初始位置移动到此方格;
- 玩家不可以从此方格移动到目标位置。
也就是说满足性质的方格X表示
- 可以从S点到达
- 从该点可以到达T
所以解题思路可以先从S开始深搜遍历,统计经过的所有点,这些点构成的集合都满足条件1。然后在对点集进行遍历,对每个点进行判断,是否可以到达点T,如果不可以,将结果+1,最后输出结果就是所求答案。
优化方法:暂时想到的优化方法是使用剪枝,就是在S深搜之后,获得点集P,在对点P中的所有点进行遍历时,设置一个标记数组,这个标记表示是否可以到达终点T;这时候,如果点A标记为可以到达终点T,点B的下一个点是点A,那么点B同样可以到达终点T。对点集P中的点每次进行深搜遍历时,每一次遍历都会对路径上的所有点设置标记,这样如果某次遍历遍历到了一个中间点Q,并且这个点Q正好是被标记的点,那么就可以直接结束遍历,并且设置该点为标记点即可。
2. 解题步骤
- 从S点做深搜,得到S可以到达的点集P。
- 判断点集P中是否有终点T,如果没有直接输出“I’m stuck”;
- 如果P中含有点T,则对P中的每个点进行遍历,判断其是否可以到达终点T
- 统计符合条件的点的个数,输出
3. 示例代码
这部分代码写的有些乱,需要整理
public class Question5 {
private static final int MAP_SIZE = 50;
private static char[][] map = new char[MAP_SIZE + 1][];
private static Position startPosition = null;
private static Position endPosition = null;
private static int n, m;
/**
* 获取点的移动量
*
* @param x 横坐标
* @param y 纵坐标
* @return 横纵坐标移动分量数组
*/
private static int[][] direct(int x, int y) {
int[][] result;
switch (map[x][y]) {
case '-':
result = new int[][]{
{
0,-1}, {
0,1}};
break;
case '|':
result = new int[][]{
{
-1,0}, {
1,0