hihocoder #1519 逃离迷宫II

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi被坏女巫抓进里一间有N x M个格子组成的矩阵迷宫。

有些格子是小Hi可以经过的,我们用’.’表示;有些格子上有障碍物小Hi不能经过,我们用’#’表示。小Hi的起始位置用’S’表示,他需要到达用’T’表示的格子才能逃离迷宫。

麻烦的是小Hi被坏女巫施了魔法,他只能选择上下左右某一个方向,沿着这个方向一直走,直到遇到障碍物或者迷宫边界才能改变方向。新的方向可以是上下左右四个方向之一。之后他还是只能沿着新的方向一直走直到再次遇到障碍物或者迷宫边界……

小Hi想知道他最少改变几次方向才能逃离这个迷宫。
输入

第一行包含两个整数N和M。 (1 <= N, M <= 500)

以下N行每行M个字符,代表迷宫。
输出

一个整数代表答案。如果小Hi没法逃离迷宫,输出-1。
样例输入

5 5
S.#.T  
.....  
.....  
.....  
.....

样例输出

2

  一开始,我想的太复杂了,用BFS逐个扫,一个一个格子走。后来发现代码量太大了,写了半天最后wrong answer。。。于是,一怒之下改了整个程序。下面是主要得思路:
  之前我是一步步走,逐个试,如上样例中,先是(0,0),然后(1,0),(0,1),(2,0),(1,1) ……;后来发现其实不需要,因为在遇到障碍物之前不需要转弯,索性直接让它一路走到黑,遇到障碍再做处理好了。如上样例中,先是(0,0),然后(4,0),(0,1),(4,4),(4,1),(4,0)就到T了。改了程序后,果断AC,下面是AC代码:
  


#include<iostream>
#include<map>
#include<string>
#include<string.h>
#include<queue>
#include<stack>
#include<vector>
#include <cstdio>
#include<fstream>
#include<algorithm>
#include<sstream>
#include<set>
#include<iterator>
using namespace std;

struct node {
    int x;
    int  y;
    int fangx;//1,2,3,4 上左下右
    int step;
    node(int xt=0, int yt=0, int st=0,int fx = 0) :x(xt), y(yt), fangx(fx),step(st) {}
};

int zh[4][2] = { { -1,0 },{0,-1},{1,0},{0,1} };//转换方向用的数组,顺序是上左下右
const  int maxn = 510;
char ditu[maxn][maxn];
bool visit[maxn][maxn];//保存访问的信息
queue<node > duilie;
int M = 0, N = 0;

int walk(node &n,int &flag)//走直线,注意这里是引用,即会改变原来的值
{
    while (ditu[n.x][n.y] != '#'&&n.x<M&&n.y<N&&n.x>-1 && n.y>-1) {//未遇到障碍或者边界
        n.x = n.x+zh[n.fangx][0];
        n.y = n.y+zh[n.fangx][1];
        if (ditu[n.x][n.y] == 'T')//到达T
        {
            flag = 1; //标记为1,表示找到
            break;
        }
    }
    if (!flag) {//未到达T,表示遇到障碍物或边界,此时正在障碍物或边界上,因此需要往原来的方向退一步,才能做转向
        n.x = n.x - zh[n.fangx][0];
        n.y = n.y - zh[n.fangx][1];
    }
    return 0;
}

int LuShi()
{
    int startX = 0, startY = 0, endX = 0, endY = 0;
    memset(visit, false, sizeof(visit));//初始化为false,都为访问
    cin >> M >> N;
    for (int i = 0; i < M; i++)
    {
        for (int j = 0; j < N; j++)
        {
            cin >> ditu[i][j];
            if (ditu[i][j] == 'S') { startX = i, startY = j; }//记录起始位置
        }
    }
    node st(startX, startY, 0);//初始位置的节点,节点位置和转向的步数,此时当然为0
    for (int i = 0; i < 4; i++)
    {
        st.fangx = i;//给初始节点各个方向
        duilie.push(st);//放入队列中
    }
    visit[startX][startY] = true;//初始位置标记访问
    while (!duilie.empty())
    {
        node n = duilie.front();
        int flag = 0;
        duilie.pop();
        walk(n,flag);//让n一路走到黑
        if (flag) {//如果找到了
            cout << n.step << endl;//输出转向的步数
            return 0;
        }
        else
        {
            if (!visit[n.x][n.y]) {//如果走到的位置没有被访问,
                visit[n.x][n.y] = true;//标记访问
                n.step++;//此处需要转向了,因此+1
                int fx = n.fangx;//保存原来的方向
                for (int i = 0; i < 4; i++)
                {
                    if (i != fx) {//确保新的方向不是原方向,因为再走原来的方向是没有意义的
                        n.fangx = i;
                        duilie.push(n);
                    }
                }
            }
        }
    }
    cout << "-1" << endl;//如果一直没有找到,说明不可达
    return 0;
}

int main()
{
    streambuf * inbuf = cin.rdbuf((new ifstream("C:\\Users\\yzc\\Desktop\\input.txt"))->rdbuf());//重定向,OJ时将它注释掉
    //cout << LuShi() << endl;
    LuShi();
    system("pause");
    return 0;
}
点赞