题目

Problem Description

Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向.
比如下面的例子里,一开始楼梯在竖直方向,一分钟以后它移动到了水平方向,再过一分钟它又回到了竖直方向.Harry发现对他来说很难找到能使得他最快到达目的地的路线,这时Ron(Harry最好的朋友)告诉Harry正好有一个魔法道具可以帮助他寻找这样的路线,而那个魔法道具上的咒语,正是由你纂写的.

Input

测试数据有多组,每组的表述如下:
第一行有两个数,M和N,接下来是一个M行N列的地图,'*'表示障碍物,'.'表示走廊,'|'或者'-'表示一个楼梯,并且标明了它在一开始时所处的位置:'|'表示的楼梯在最开始是竖直方向,'-'表示的楼梯在一开始是水平方向.地图中还有一个'S'是起点,'T'是目标,0<=M,N<=20,地图中不会出现两个相连的梯子.Harry每秒只能停留在'.'或'S'和'T'所标记的格子内.

Output

只有一行,包含一个数T,表示到达目标的最短时间.
注意:Harry只能每次走到相邻的格子而不能斜走,每移动一次恰好为一分钟,并且Harry登上楼梯并经过楼梯到达对面的整个过程只需要一分钟,Harry从来不在楼梯上停留.并且每次楼梯都恰好在Harry移动完毕以后才改变方向.

Sample Input

5 5
**..T
**.*.
..|..
.*.*.
S....

Sample Output

7

## Hint

地图如下

题解

猛一看,这道题思路非常清晰,二维矩阵中进行BFS,根据时间来判断梯子的走向。
然而交了好多次都没AC
开始是由于直接复制BFS的模板,结果忘记改maxn导致超时(竟然不是RE)
后来就是莫名其妙的WA
再看一遍题,可以发现一个很关键的地方
题目中没有说如果路径不存在则输出-1
也就是说,不管怎么样一定存在路径

那么我们仔细想下,类似

S|T

这样的迷宫显然是没有路径的,如果通过绕路的方式,可以发现在回到该位置后,梯子的方向不变。
那么,真相只有一个:可以原地等待一步

明白了这点,稍加修改就可以得到符合题意得算法

另外有一点需要注意:
由于等待改变了BFS层数的先后顺序(等待的层数额外加1),这回破坏BFS天然的顺序
因此,要采用优先队列来存储

代码

/*
By:OhYee
Github:OhYee
Email:oyohyee@oyohyee.com
Blog:http://www.cnblogs.com/ohyee/

かしこいかわいい?
エリーチカ!
要写出来Хорошо的代码哦~
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <vector>
#include <list>
#include <queue>
#include <stack>
using namespace std;

//DEBUG MODE
#define debug 0

//循环
#define REP(n) for(int o=0;o<n;o++)

const int maxn = 30;
int n,m;
char Map[maxn][maxn];

#if debug
pair<int,int> last[maxn][maxn];
#endif

const int delta[4] = {1,-1,0,0};

struct point {
    int x,y;
    int dis;//楼梯是否已变化
    point(int a,int b,int c) {
        x = a;
        y = b;
        dis = c;
    }
    bool operator < (const point &rhs) const {
        return dis>rhs.dis;
    }
};

int BFS(int s1,int s2,int v1,int v2) {
    priority_queue<point> Q;
    int dis[maxn][maxn];
    memset(dis,-1,sizeof(dis));

    Q.push(point(s1,s2,false));
    dis[s1][s2] = 0;

    while (!Q.empty()) {
        point temp = Q.top();
        Q.pop();

        int x = temp.x;
        int y = temp.y;
        int dist = temp.dis;

        REP(4) {
            int xx = x + delta[o];
            int yy = y + delta[3 - o];
            int dd = dist + 1;

            if (xx < 0 || xx >= m || yy < 0 || yy >= n || Map[xx][yy] == '*')
                continue;
            if (Map[xx][yy] == '-' || Map[xx][yy] == '|') {//是梯子
                if (x == xx) {//水平方向移动
                    //需要等待一步
                    if ((Map[xx][yy] == '-' && dist % 2 == 1) || (Map[xx][yy] == '|' && dist % 2 != 1))
                        dd++;
                    yy += yy - y;
                } else {//竖直方向移动
                    //需要等待一步
                    if ((Map[xx][yy] == '|' && dist % 2 == 1) || (Map[xx][yy] == '-' && dist % 2 != 1))
                        dd++;
                    xx += xx - x;
                }
            }
            if (xx < 0 || xx >= m || yy < 0 || yy >= n || Map[xx][yy] != '.')
                continue;

            if (dis[xx][yy] == -1) {
                dis[xx][yy] = dd;
#if debug
                last[xx][yy] = pair<int,int>(x,y);
#endif
                if (xx == v1 && yy == v2)
                    break;
                Q.push(point(xx,yy,dd));

            }
        }
    }

#if debug
    pair<int,int> w;
    w = pair<int,int>(v1,v2);
    while (!(w.first == s1 && w.second == s2)) {
        printf("%d %d\n",w.first,w.second);
        w = last[w.first][w.second];
    }
#endif

    return dis[v1][v2];
}

bool Do() {
    int s1,v1;
    int s2,v2;
    if (scanf("%d%d\n",&m,&n) == EOF)
        return false;
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++) {
            scanf("\n%c\n",&Map[i][j]);
            if (Map[i][j] == 'S') {
                s1 = i;
                s2 = j;
                Map[i][j] = '.';
            }
            if (Map[i][j] == 'T') {
                v1 = i;
                v2 = j;
                Map[i][j] = '.';
            }
        }

#if debug
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++)
            printf("%c",Map[i][j]);
        printf("\n");
    }
#endif

    printf("%d\n",BFS(s1,s2,v1,v2));
    return true;
}


int main() {
    while (Do());
    return 0;
}