D-wyh的迷宫
链接:https://www.nowcoder.com/acm/contest/93/D
来源:牛客网
给你一个n*m的迷宫,这个迷宫中有以下几个标识:
s代表起点
t代表终点
x代表障碍物
.代表空地
现在你们涵哥想知道能不能从起点走到终点不碰到障碍物(只能上下左右进行移动,并且不能移动到已经移动过的点)。
输入描述:
输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,对于每一组测试数据,第一行输入2个数n和m(1<=n,m<=500)
接下来n行,每行m个字符代表这个迷宫,每个字符都是上面4个中的一种
数据保证只有一个起点和一个终点
输出描述:
对于每一组测试数据,如果可以的话输出YES,不可以的话输出NO
解析
首先这题很差劲啊,对Java如此的不友好,丢雷楼母的出题人。C++做这个题dfs妥妥的过了,最重要的是都不用剪纸都能过,mmmp。 而对于Java来说,会栈溢出,剪枝也不行,必须用bfs才能过。
这是一道经典的遍历的题,dfs或bfs都可过,最重要的是记住,迷宫类的题在回溯时走过的点不用恢复为未走过,因为从这个点往各个方向走,我们都已考察过了,如果回溯时恢复成未考察的状态,则下次走到这个点又要重复的判断,势必会超时。
代码
Java
dfs栈溢出了(代码注释部分,感兴趣的可以尝试如何A掉)。bfs过了。
package com.special.DongBeiLinYeSpring;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
/**
* Create by Special on 2018/4/10 20:10
*/
public class ProD {
static int startX, startY, endX, endY, n, m;
static boolean[][] vis;
static char[][] maps;
static boolean flag;
static int[][] steps = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
static boolean isValid(int x, int y){
return !(x < 0 || x >= n || y < 0 || y >= m);
}
// static void dfs(int x, int y){
if(x == endX && y == endY){
flag = true;
return;
}
int tempX, tempY;
for(int i = 0; i < 4; i++){
tempX = x + steps[i][0];
tempY = y + steps[i][1];
if(isValid(tempX, tempY) && !vis[tempX][tempY] && maps[tempX][tempY] != 'x'){
vis[tempX][tempY] = true;
dfs(tempX, tempY);
if(flag){
return;
}
}
}
// if(isValid(x, y) && !vis[x][y] && maps[x][y] != 'x'){
// if(x == )
// vis[x][y] = true;
// dfs(x - 1, y);
// dfs(x + 1, y);
// dfs(x, y - 1);
// dfs(x , y + 1);
// }
// }
static class Node{
int x;
int y;
public Node(int x, int y){
this.x = x;
this.y = y;
}
}
static void bfs(int x, int y){
Queue<Node> queue = new LinkedList<>();
queue.add(new Node(x, y));
vis[x][y] = true;
while(!queue.isEmpty()){
Node node = queue.poll();
if(node.x == endX && node.y == endY){
flag = true;
break;
}
int tempX, tempY;
for(int i = 0; i < 4; i++){
tempX = node.x + steps[i][0];
tempY = node.y + steps[i][1];
if(isValid(tempX, tempY) && !vis[tempX][tempY] && maps[tempX][tempY] != 'x'){
vis[tempX][tempY] = true;
queue.offer(new Node(tempX, tempY));
}
}
}
}
public static void main(String[] args){
FastScanner input = new FastScanner();
PrintWriter out = new PrintWriter(System.out);
int t = input.nextInt();
while(t-- > 0) {
n = input.nextInt();
m = input.nextInt();
maps = new char[n][m];
vis = new boolean[n][m];
flag = false;
for(int i = 0; i < n; i++){
String str = input.next();
maps[i] = str.toCharArray();
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(maps[i][j] == 's'){
startX = i;
startY = j;
}else if(maps[i][j] == 't'){
endX = i;
endY = j;
}
}
}
bfs(startX, startY);
out.println(flag ? "YES" : "NO");
}
out.close();
}
}
C++
同样的代码,C++可过。。无奈
#include <bits/stdc++.h>
using namespace std;
const int maxn = 500 + 5;
char maps[maxn][maxn];
bool vis[maxn][maxn];
int n, m, sX, sY, eX, eY;
int steps[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
bool flag;
bool isValid(int x, int y){
return !(x < 0 || x >= n || y < 0 || y >= m);
}
void dfs(int x, int y){
if(x == eX && y == eY){
flag = true;
return;
}
int tempX = 0, tempY = 0;
for(int i = 0; i < 4; i++){
tempX = x + steps[i][0];
tempY = y + steps[i][1];
if(isValid(tempX, tempY) && !vis[tempX][tempY] && maps[tempX][tempY] != 'x'){
vis[tempX][tempY] = true;
dfs(tempX, tempY);
if(flag){
return;
}
}
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d %d", &n, &m);
memset(vis, false, sizeof(vis));
flag = false;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
scanf("%c", &maps[i][j]);
if(maps[i][j] == 's'){
sX = i;
sY = j;
}else if(maps[i][j] == 't'){
eX = i;
eY = j;
}
}
}
dfs(sX, sY);
if(flag){
printf("YES");
}else{
printf("NO");
}
}
}
优化
我们可以利用x来表示已走过的点,所以我们把走过的点赋值为x,则不用额外的vis了。