题目描述
曾经的我不过是一介草民,混迹市井,默默无名。直到我被罗马的士兵从家乡捉走丢进竞技场....
对手出现了,我架紧盾牌想要防御,只觉得巨大的冲击力有如一面城墙冲涌而来,击碎了我的盾牌,我两眼发昏,沉重的身躯轰然倒地。
—— 我好想逃
但罗马最大的竞技场,哪有这么容易逃得掉。工程师们早就在地上装了传送机关,虽不会伤人,却会将站在上面的人传到它指向的位置。若是几个传送机关围成一个环,不小心踩在上面的人就会被一圈圈的反复传送...
想到这里,我不由得打了个寒颤。必须避开这些危险的地方!
输入格式
-
第一行输入两个整数 n 和 m,表示迷宫的长和宽
-
接下来 n 行,每行 m 个字符,用于描述迷宫构造,每个字符可能为以下几种
-
.(小数点)表示空地,玩家在空地时可以选择往[上,下,左,右]中的某个方向移动一格 -
U,D,L,R分别表示朝向[上,下,左,右]的传送带,站在传送带上的人会被强制移动到其指向的下一个位置- 如果下一个位置还是传送带,会被继续传下去
- 如果传送带指向迷宫外,玩家会撞在墙上昏过去,游戏结束,无法再到达出口
-
O表示迷宫出口
-
输出格式
- 输出一个数字,表示迷宫中有多少个位置,当玩家移动到此处时,无论接下来如何移动都无法再到达出口。
(传送带、空地、出口都算一个位置)
输入样例
5 5
.....
.RRD.
.U.DR
.ULL.
....O
输出样例
10
数据范围
- 1≤n,m≤1051≤n,m≤105
- 1≤n⋅m≤1051≤n⋅m≤105
- 保证每个迷宫中有且仅有一个出口
思路
定义两个二维数组:
static int[][] flag;//是否可达
static int[][] used;//是否遍历过
找到O出口位置portX和portY
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
if(data[i][j]=='O'){
portX=i;
portY=j;
break;
}
}
}
从出口处DFS遍历data迷宫,遇到一个可达位置,flag置为1,继续向上下左右位置判断是否可达
private static void traverse(int x,int y,char[][] data){
if(x<0||y<0||x>=data.length||y>=data[0].length){
return;
}
if(used[x][y]==1){
return;
}
used[x][y]=1;//标记为访问过
flag[x][y]=1;//标记为可达
//找到一个可达地点,继续向上下左右判断是否可达
//向上判断
if(x-1>=0&&(data[x-1][y]=='D'||data[x-1][y]=='.')){//向上判断时该处是向下,说明也是可达,下左右以此类推
traverse(x-1,y,data);
}
//向下判断
if(x+1< data.length&&(data[x+1][y]=='U'||data[x+1][y]=='.')){
traverse(x+1,y,data);
}
//向左判断
if(y-1>=0&&(data[x][y-1]=='R'||data[x][y-1]=='.')){
traverse(x,y-1,data);
}
//向右判断
if(y+1<data[0].length&&(data[x][y+1]=='L'||data[x][y+1]=='.')){
traverse(x,y+1,data);
}
}
最后统计所有flag=0的不可达位置,完整代码如下:
public class Main {
static int[][] flag;//是否可达
static int[][] used;//是否遍历过
public static int solution(int N, int M, char[][] data) {
// Edit your code here
int portX=0,portY=0;
flag = new int[N][M];
used = new int[N][M];
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
if(data[i][j]=='O'){
portX=i;
portY=j;
break;
}
}
}
flag[portX][portY]=1;
traverse(portX,portY,data);
int result=0;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
if(flag[i][j]==0){
result++;
}
}
}
return result;
}
private static void traverse(int x,int y,char[][] data){
if(x<0||y<0||x>=data.length||y>=data[0].length){
return;
}
if(used[x][y]==1){
return;
}
used[x][y]=1;//标记为访问过
flag[x][y]=1;//标记为可达
//找到一个可达地点,继续向上下左右判断是否可达
//向上判断
if(x-1>=0&&(data[x-1][y]=='D'||data[x-1][y]=='.')){
traverse(x-1,y,data);
}
//向下判断
if(x+1< data.length&&(data[x+1][y]=='U'||data[x+1][y]=='.')){
traverse(x+1,y,data);
}
//向左判断
if(y-1>=0&&(data[x][y-1]=='R'||data[x][y-1]=='.')){
traverse(x,y-1,data);
}
//向右判断
if(y+1<data[0].length&&(data[x][y+1]=='L'||data[x][y+1]=='.')){
traverse(x,y+1,data);
}
}
public static void main(String[] args) {
// Add your test cases here
char[][] pattern = {
{'.', '.', '.', '.', '.'},
{'.', 'R', 'R', 'D', '.'},
{'.', 'U', '.', 'D', 'R'},
{'.', 'U', 'L', 'L', '.'},
{'.', '.', '.', '.', 'O'}
};
System.out.println(solution(5, 5, pattern) == 10);
}
}
本题关键点:找到一个可达位置时,再向上判断,如果上面的位置是D(向下),说明上面的位置也是可达的,则继续向上递归;如果下面的位置是U,说明下面的位置也是可达的.....