zoukankan      html  css  js  c++  java
  • 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
    ",mmin);
            else
                printf("-1
    ");    //否则输出-1 
            
        }
        return 0;
     } 
  • 相关阅读:
    Java如何遍历二维数据
    Java标识符中常见的命名规则
    Java中常量的概念
    Java的数据类型
    Java中的方法是什么以及方法的书写格式
    Java中什么是构造方法
    Java中继承的概念
    Java中的匿名对象代码实例
    Java集合案例(产生不重复随机数)
    Java中集合的初等案例
  • 原文地址:https://www.cnblogs.com/hellocheng/p/7821316.html
Copyright © 2011-2022 走看看