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

逃离迷宫

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
 
  
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>



转载于:https://www.cnblogs.com/sixdaycoder/p/4348386.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值