ACM-BFS之逃离迷宫——hdu1728

来源:互联网 发布:猫鼠游戏结局知乎 编辑:程序博客网 时间:2024/06/03 20:41
逃离迷宫
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1728
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13583 Accepted Submission(s): 3224

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


广搜题目,其实用深搜也可以做。

我刚开始向这道题 方向判断用两个数来代替,0代表列向,1代表横向。

然后根据dis数组赋值为 左、上、右、下,这样i%2==0时则是列向行走,i%2==1时为横向行走

经过实践证明,这么做时错误的。。o(╯□╰)o啊~~~~

好吧,关键在于,判断一个点可以不可以走,不仅看它是否在界内或者是否是墙。

而是看曾经到达这个点的转弯次数是否大于此次到达这个点的转弯次数。

因此,如果曾经到达这个点最小转弯次数等于这次到达这个点最小转弯次数。

那也要将这个点入队列。

就是说->到达一个点的转弯次数相同,但两次的方向可能不同。

So,如果用两个方向来代替四个方向,则无法实现这种情况。


And,End

/*Author:TreeFrom: http://blog.csdn.net/lttree逃离迷宫hdu 1728BFS——广度优先搜索迷宫转弯次数限定*/#include <iostream>#include <queue>#include <string.h>using namespace std;struct Coor{    int x,y,fx,tn;};int n,m,turn,f_x,f_y,dis[4][2]={-1,0,0,-1,1,0,0,1};char mapp[101][101];int vis[101][101];bool isout(int x,int y){    if( x<1 || x>n || y<1 || y>m )  return 1;    if( mapp[x][y]=='*' )   return 1;    return 0;}void bfs(int sx,int sy){    int i;    memset(vis,-1,sizeof(vis));    queue <Coor> q;    Coor pre,lst;    pre.x=sx;    pre.y=sy;    pre.fx=-1;    pre.tn=0;    vis[pre.x][pre.y]=0;    q.push(pre);    while( !q.empty() )    {        pre=q.front();        q.pop();        for(i=0;i<4;++i)        {            lst.x=pre.x+dis[i][0];            lst.y=pre.y+dis[i][1];            // 判断坐标是否越界或者撞墙等            if( isout(lst.x,lst.y) )    continue;            // 方向是否改变,-1代表它上一步是起点            if( pre.fx!=-1 && pre.fx!=i )    lst.tn=pre.tn+1;            else    lst.tn=pre.tn;            if( lst.tn>turn )   continue;            if(lst.x==f_x && lst.y==f_y)    {cout<<"yes"<<endl;return;}            // 如果曾经到这里转弯次数大于这次到这里转弯次数,则该点可再进队列            if( vis[lst.x][lst.y]==-1 || vis[lst.x][lst.y]>=lst.tn )            {                lst.fx=i;                vis[lst.x][lst.y]=lst.tn;                q.push(lst);            }        }    }    cout<<"no"<<endl;}int main(){    int test,i,j,s_x,s_y;    cin>>test;    while(test--)    {        cin>>n>>m;        for(i=1;i<=n;++i)            for(j=1;j<=m;++j)                cin>>mapp[i][j];        // 注意别扭的输入        cin>>turn>>s_y>>s_x>>f_y>>f_x;        bfs(s_x,s_y);    }    return 0;}



0 0