杭电1728————一直WA的BFS(有思维惯性带来的陷阱)

来源:互联网 发布:手机破解压缩文件软件 编辑:程序博客网 时间:2024/05/01 07:11

逃离迷宫

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对应行。
 

Output
  每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。
 

Sample Input
25 5...***.**...........*....1 1 1 1 35 5...***.**...........*....2 1 1 1 3
 

Sample Output
noyes
 

Source
“网新恩普杯”杭州电子科技大学程序设计邀请赛


一开我就很单纯的以为是BFS+一些前驱的小应用而已....写下了如下代码过了很多组测试数据不断WA    OTZ

<span style="font-family:Microsoft YaHei;font-size:14px;">#include <cstdio>#include <cstring>#include <queue>#define maxn 105using 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 105using 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;elsemaze[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");elseprintf("no\n");}}return 0;}</span>



0 0
原创粉丝点击