逃离迷宫
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 15281 Accepted Submission(s): 3692
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, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,y1, y2对应行。
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m),其中k表示gloria最多能转的弯数,(x1, y1), (x2, y2)表示两个位置,其中x1,x2对应列,y1, y2对应行。
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
一开我就很单纯的以为是BFS+一些前驱的小应用而已....写下了如下代码过了很多组测试数据不断WA OTZ
<span style="font-family:Microsoft YaHei;font-size:14px;">#include <cstdio>
#include <cstring>
#include <queue>
#define maxn 105
using namespace std;
/*到达的时候转弯数小于maxturn就行*/
struct point{
int x,y;
int turn;/*转弯个数*/
int turnx,turny;/*记录向哪转的方向*/
};
int dx[4] = {1,-1,0,0},dy[4] = {0,0,1,-1};
int row,col;
int maze[maxn][maxn];
int vis[maxn][maxn];
int maxturn,sx,sy,ex,ey;/*start_x,start_y,end_x,end_y*/
int find;
queue<struct point> Q;
void read_maze()
{
char str[maxn];
memset(vis,0,sizeof(vis));
getchar();
for(int i = 1 ; i <= row ; i++)
{
scanf("%s",str);
for(int j = 0 ; j < strlen(str) ; j++)
{
if(str[j] == '*')
maze[i][j+1] = 1;
else
maze[i][j+1] = 0;
}
getchar();
}
scanf("%d",&maxturn);
scanf("%d%d%d%d",&sy,&sx,&ey,&ex);
}
int inborder(int x,int y)
{
int flag = 1;
if(x < 1 || x > row || y < 1 || y > col)
flag = 0;
if(maze[x][y] == 1)
flag = 0;
return flag;
}
void BFS()
{
struct point now,next;
while(!Q.empty())
Q.pop();/*每次搜索前清空队列*/
now.x = sx;
now.y = sy;
now.turn = 0;
now.turnx = 0;
now.turny = 0;
vis[sx][sy] = 1;
Q.push(now);
while(!Q.empty())
{
now = Q.front();
Q.pop();
for(int k = 0 ; k < 4 ; k++)
{
next.x = now.x + dx[k];
next.turnx = dx[k];
next.y = now.y + dy[k];
next.turny = dy[k];
if(inborder(next.x,next.y) && !vis[next.x][next.y])
{
vis[next.x][next.y] = 1;
if(next.turnx == now.turnx && next.turny == now.turny)
/*和之前走的方向不一致也就是说转弯了*/
next.turn = now.turn;
else
next.turn = now.turn + 1;
Q.push(next);
if(next.x == ex && next.y == ey && next.turn > maxturn + 1)
{
find = 0;
return ;
}
if(next.x == ex && next.y == ey && next.turn <= maxturn + 1)
{
find = 1;
return ;
}
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&row,&col);
read_maze();/*经测试正确*/
find = 0;/*默认找不到*/
BFS();
if(find)
printf("yes\n");
else
printf("no\n");
}
return 0;
}</span>
无限WA是什么情况...想不明白想不明白..(陷入思维定式了肯定想不明白)
只好百度了.....看到了一个AC代码,竟然没有vis数组进行标记,但是作者也没说为什么。又看了一下别人的,大致有了了解。
如图所示:
假设4是目标位置。
假设在2这个坐标转弯数是5,是向下走的,那么4的转弯数是5
假设在3这个坐标转弯数是5,是向下走的,那么4的转弯数就是6
2 . 3 这两个点很明显都是4的上一层(从搜索树来看)但是如果3比2先入队,那么3就先出队列,把4遍历过,4的转弯数就是6了,并且把4标记为已经遍历,那么2后出队就无法遍历4,但是按照假设很显然从2到4的转弯数最少
所以新建一个moveto[i][j]数组表示到达i,j坐标的最小转弯数(初始化为一个很大的数)
<span style="font-family:Microsoft YaHei;font-size:14px;">when
moveto[i][j] >= 下一入队结点的转弯数
{
moveto[i][j] = 下一结点转弯数;
下一结点入队;
}
</span>
亲测46MS
<span style="font-family:Microsoft YaHei;font-size:14px;">#include <cstdio>
#include <cstring>
#include <queue>
#define maxn 105
using namespace std;
/*到达的时候转弯数小于maxturn就行*/
struct point{
int x,y;
int turn;/*转弯个数*/
int dir;
};
int dir[4][2] = {{0,1},{-1,0},{1,0},{0,-1}};
int row,col;
int maze[maxn][maxn];
int moveto[maxn][maxn];/*记录了移动到(i,j)处需要的转弯数*/
int maxturn,sx,sy,ex,ey;/*start_x,start_y,end_x,end_y*/
int find;
queue<struct point> Q;
void read_maze()
{
char str[maxn];
for(int i = 0 ; i <= row ; i++)
for(int j = 0 ; j <= col ; j++)
moveto[i][j] = 10000;
getchar();
for(int i = 1 ; i <= row ; i++)
{
scanf("%s",str);
for(int j = 0 ; j < strlen(str) ; j++)
{
if(str[j] == '*')
maze[i][j+1] = 1;
else
maze[i][j+1] = 0;
}
getchar();
}
scanf("%d",&maxturn);
scanf("%d%d%d%d",&sy,&sx,&ey,&ex);
}
int inborder(int x,int y)
{
int flag = 1;
if(x < 1 || x > row || y < 1 || y > col)
flag = 0;
if(maze[x][y] == 1)
flag = 0;
return flag;
}
void BFS()
{
struct point pre,next;
while(!Q.empty())
Q.pop();/*每次搜索前清空队列*/
pre.x = sx;
pre.y = sy;
pre.turn = 0;
pre.dir = -1;/*第一次移动不算转弯*/
moveto[sx][sy] = 0;/*初始化转弯数为0*/
Q.push(pre);
while(!Q.empty())
{
pre = Q.front();
Q.pop();
for(int k = 0 ; k < 4 ; k++)
{
next = pre;
next.x += dir[k][0];
next.y += dir[k][1];
if(!inborder(next.x,next.y))
continue;
if(next.dir != k && next.dir != -1)/*==-1是初始点不用算转弯数*/
next.turn ++;/*相当于next.turn = pre.turn + 1;*/
if(next.turn > maxturn)
continue;
if(moveto[next.x][next.y] >= next.turn)
{
next.dir = k;/*前边的判断全部是否定的说明是没有转弯的*/
moveto[next.x][next.y] = next.turn;
Q.push(next);
}
if(next.x == ex && next.y == ey)
{
find = 1;
return ;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&row,&col);
read_maze();/*经测试正确*/
find = 0;/*默认找不到*/
if(sx == ex && sy == ey)
printf("yes\n");
else
{
BFS();
if(find)
printf("yes\n");
else
printf("no\n");
}
}
return 0;
}</span>