。。。

导航

hdu 2364 Escape【模拟优先队列】【bfs】

http://acm.hdu.edu.cn/showproblem.php?pid=2364

题意:从唯一的起点‘@’出发,输出到达边界的步数,如果不能到达,输出-1。每走下一步,优先选择转弯的方向,只能直走(两边都是障碍物)时,才选择直走方向,重点是,不能往回走。

判断能否下一步转弯的思路是:先将四个方向用0,1,2,3标记,如果当前步方向和下一步方向相等,当前步方向+1,方向-1,如果这两个方向上同时存在障碍物,说明只能直走,加入队列;如果当前步方向和下一步方向不相等时,直接加入队列。这道题我理解错一个地方,它走过的地方其实可以再走,只是,走过的方向不能再走,所以当我用二维数组标记该点是否走过时,是有问题滴,因为它直接就将四个方向都标记为已经走过,正解应该是,在二维基础上多加一维,用以标记该点的四个方向。

~~~这道题,为什么我先判断只能直走的情况,再判断转弯的情况呢~~因为我对 c++的优先队列并不熟悉,就在函数内部直接判断的时候模拟优先队列操作过程,如果不用优先队列,直接用if(nowq.father!=i)Q.push(nextq);会将除了往回走的方向以外的三个方向直接无序加入,而此题的要求是,优先转弯,不能转弯再直走。

ps:昨天本来想把这道题作为我的双十一大礼包的,结果写了一个下午,都没有写出来,自己好菜啊~~~

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define N 85
int map[N][N],mmin,flag,n,m,vis[N][N][4];
char str[N][N];
typedef struct node{
    int x,y;
    int father;//记录方向 
    int step;//记录步数 
}node;

int bfs(int x,int y)
{
    int k[4][2]={0,1,-1,0,0,-1,1,0};
    int nx,ny,xi,yi,x1,y1,x2,y2;
    node nextq,nowq;
    memset(vis,0,sizeof(vis));//初始化标记数组 
    queue<node>Q;
    flag = 0;//标记是否能够成功到达 
    nowq.father = -1;//起点的方向是-1,区别其它点 
    nowq.x = x;
    nowq.y = y;
    nowq.step = 0;//初始化起点 
    vis[x][y][0]=1,vis[x][y][1]=1;//起点标记为已经走过 
    vis[x][y][2]=1,vis[x][y][3] = 1;
    Q.push(nowq);//将起点加入队列 
    while(!Q.empty())
    {
        nowq = Q.front() ;
        Q.pop();
        if(nowq.x == 0||nowq.y == 0||nowq.x == n-1||nowq.y == m-1)//到达出口 
        {
            if(str[nowq.x][nowq.y]!='#')
                flag = 1;//能够成功到达 
            return nowq.step ;
        }
        for(int i = 0; i < 4; i ++)
        {
            nx = nowq.x + k[i][0];
            ny = nowq.y + k[i][1];
            if(nx < 0||ny < 0||nx > n-1||ny > m-1||str[nx][ny]=='#'||vis[nx][ny][i])
                continue;    //不能越界,不能是墙,不能已经是访问过的点 
            nextq.x = nx;
            nextq.y = ny;
            nextq.father = i;//记录父点到当前点的方向 
            nextq.step = nowq.step + 1;//步数加1 
             if(nowq.father%2 == i%2)
            {
                if(nowq.father == i)
                {
                    x1 = nowq.x + k[(i+1)%4][0];
                    y1 = nowq.y + k[(i+1)%4][1];
                    x2 = nowq.x + k[(i-1+4)%4][0];
                    y2 = nowq.y + k[(i-1+4)%4][1];
                    if(str[x1][y1]!='.'&&str[x2][y2]!='.')//如果当前位置左右两边都不能走即只能直走 
                    {
                        vis[nx][ny][i] = 1;//标记该方向为已经访问过
                        Q.push(nextq);
                    }
                }
            }
            else
            {
                    vis[nx][ny][i] = 1;
                    Q.push(nextq);
            }    
        }
    }
    return -1;
}
int main()
{
    int t,i,j,x,y;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(str,0,sizeof(str));
        for(i = 0; i < n; i ++)
        {
            scanf("%s",str[i]);
            for(j = 0; j < m; j ++)
            {
                if(str[i][j] == '@')//找到起点,存入x,y. 
                {
                    x = i;
                    y = j;
                }
            }
        }
        mmin = bfs(x,y);//返回步数 
        if(flag)//如果能到达出口。输出步数 
            printf("%d\n",mmin);
        else
            printf("-1\n");    //否则输出-1 
        
    }
    return 0;
 } 

 

posted on 2017-11-12 12:02  大学僧  阅读(167)  评论(0编辑  收藏  举报