/*
思路:
1)从起点开始搜索,直到找到终点。
--这个过程不允许回走,且转弯的次数不允许超过k;
--这是使用一个二维数组保存每一次走到该点的转弯次数,
--并同时判断该点是否已被访问;
--判断该点是否已被访问,可以通过前一节点的转弯次数
--加上这次移动的转弯次数来判断该点是否可行,也就是回走;
--回走的方向与原来的不同,
--那么搜索下一个是不会直接回走,
--只可能是绕弯后再一次回走,
--显然通过这种方式可以防止回走;
--所以swerve的初始化应该比k大,
--毕竟刚开始是没有转弯的。
2)找到答案后就因该直接回退,于是直接剪枝,
--也就是return,可以减掉所有的枝叶,
--方便直接返回,这里只要加个bool变量就搞定了。
*/
#include<stdio.h>
/*
使用深度优先搜索
注意:题目是从(1,1)开始,
---而程序是从(0,0)开始
m表示行数
n表示列数
x1,x2表示列
y1,y2表示行
map记录地图
swerver记录当前点已经转弯的次数,
---同时是用来判断
fourDir移动的四个方向,上下左右。
lifeAndDeath判断是否找到了出口,
也是方便最快回退。
*/
int m,n;
int k,sx1,sy1,ex2,ey2;
char map[100][100];
int swerve[100][100];
int fourDir[][2]={{-1,0},{1,0},{0,-1},{0,1}};
bool lifeAndDeath;
int main(){
void depthFirstSearch(int x,int y,int dir);
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++){
scanf("%s",map[i]);
//初始化转弯次数
for(int j=0;j<n;j++){
swerve[i][j]=11;
}
}
scanf("%d%d%d%d%d",&k,&sx1,&sy1,&ex2,&ey2);
/*
题目下标与程序下标不同,x与y的的表示也不同
深搜的起点因该是(y1,x1),
方向是任意的
*/
sy1--;
sx1--;
ey2--;
ex2--;
/*
转弯次数为0,
起始lifeAndDeath表示没有找到出口,
从起点开始搜索。
*/
swerve[sy1][sx1]=0;
lifeAndDeath=false;
depthFirstSearch(sy1,sx1,-1);
if(lifeAndDeath){
printf("yes\n");
}else{
printf("no\n");
}
}
return 0;
}
/*
x表示行
y表示列
dir表示移动的方向,-1任意方向,0上,1下,2左,3右,
---这个是跟fourDir数组相对应的
*/
void depthFirstSearch(int x,int y,int dir){
/*
这里最好写鸿沟
*/
// 转弯次数不合条件
if(swerve[x][y]>k){
return;
}
// 快速回退
if(lifeAndDeath){
return;
}
// 找到出口
if(x==ey2&&y==ex2){
lifeAndDeath=true;
return;
}
for(int i=0;i<4;i++){
/*
四个方向选择任意一个方向,
当然我们可以使用if加continue语句,
来实现剪枝,其实就是不搜索而已。
这个剪枝是把题图化,然后把图化解成树,
这是只要把图中不相干的枝去掉(剪枝),
就可以变成树,通过不同的方式剪枝到不同的树,
就可以得到不同的树,也就是答案。
*/
int a=x+fourDir[i][0];
int b=y+fourDir[i][1];
/*
思路:
从该点出发,选择i方向,
判断该方向是否合法,
不合法就剪枝。
*/
// 碰壁
if(a<0||b<0||a>=m||b>=n){
continue;
}
// 遇到障碍
if(map[a][b]=='*'){
continue;
}
// 重复访问
if(swerve[a][b]<=swerve[x][y]){
continue;
}
// 直线移动,移动次数不变
swerve[a][b]=swerve[x][y];
// 判断方向
if(dir!=-1&&i!=dir){
// 转弯,值加1
swerve[a][b]++;
}
// 可行方向
depthFirstSearch(a,b,i);
}
}
搜索题:慢慢来。
java代码:
import java.util.Scanner;
public class Main {
/*
* 给定一个m × n (m行, n列)的迷宫
* 其中k表示gloria最多能转的弯数
* 其中x1,x2对应列,y1, y2对应行
* map地图
* dir表示上下左右四个方向
*/
static int m, n, success;
static int k, x1, y1, x2, y2;
static char[][] map = new char[100][100];
static int[][] swerve = new int[100][100];
static int dir[][] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while (t-- > 0) {
m = sc.nextInt();
n = sc.nextInt();
for (int i = 0; i < m; i++) {
String str = sc.next();
for (int j = 0; j < n; j++) {
map[i][j] = str.charAt(j);
swerve[i][j] = 11;
}
}
k = sc.nextInt();
x1 = sc.nextInt() - 1;
y1 = sc.nextInt() - 1;
x2 = sc.nextInt() - 1;
y2 = sc.nextInt() - 1;
success = 0;
swerve[y1][x1]=0;
depthFirstSearch(y1, x1, -1);
if (success == 1) {
System.out.println("yes");
} else {
System.out.println("no");
}
}
}
/*
* x-x坐标
* y-y坐标
* d-direction方向0,1,2,3上下左右,
* -1表示起始方向。
* s-swerve转弯数,用来记录当前结点剩余转弯的次数。
*/
public static void depthFirstSearch(int x, int y, int d) {
// 转弯超数
if (swerve[x][y] > k) {
return;
}
// 找到答案
if (x == y2 && y == x2) {
success = 1;
return;
}
/*
* 2)以当前点为搜索源,进行搜索
*/
for (int i = 0; i < dir.length; i++) {
int a = x + dir[i][0];
int b = y + dir[i][1];
// 越界
if (a < 0 || b < 0 || a >= m || b >= n) {
continue;
}
// 遇到障碍物
if (map[a][b] == '*') {
continue;
}
// 重复访问
if (swerve[a][b] <= swerve[x][y]) {
continue;
}
// 直线行走
swerve[a][b] = swerve[x][y];
if (d != -1 && d != i) {
// 转弯
swerve[a][b]++;
}
// 可行方向
depthFirstSearch(a, b, i);
if (success == 1) {
return;
}
}
}
}
逃离迷宫
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 19352 Accepted Submission(s): 4694
Problem Description
给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?
Input
第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x 1, y 1, x 2, y 2 (1 ≤ k ≤ 10, 1 ≤ x 1, x 2 ≤ n, 1 ≤ y 1, y 2 ≤ m),其中k表示gloria最多能转的弯数,(x 1, y 1), (x 2, y 2)表示两个位置,其中x 1,x 2对应列,y 1, y 2对应行。
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x 1, y 1, x 2, y 2 (1 ≤ k ≤ 10, 1 ≤ x 1, x 2 ≤ n, 1 ≤ y 1, y 2 ≤ m),其中k表示gloria最多能转的弯数,(x 1, y 1), (x 2, y 2)表示两个位置,其中x 1,x 2对应列,y 1, y 2对应行。
Output
每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。
Sample Input
2 5 5 ...** *.**. ..... ..... *.... 1 1 1 1 3 5 5 ...** *.**. ..... ..... *.... 2 1 1 1 3
Sample Output
no yes
Source