CDOJ_149 解救小Q
原题网址:http://acm.uestc.edu.cn/#/problem/show/149
小Q被邪恶的大魔王困在了迷宫里,love8909决定去解救她。 迷宫里面有一些陷阱,一旦走到陷阱里,就会被困身亡:(,迷宫 里还有一些古老的传送
阵,一旦走到传送阵上,会强制被传送到 传送阵的另一头。
现在请你帮助love8909算一算,他至少需要走多少步才能解 救到小Q?
Input
第一行为一个整数
每组测试数据第一行为两个整数
接下来有
.
表示安全的位置#
表示陷阱,Q
表示小Q的位置L
表示love8909所在位置,
数据保证love8909只有一个,数据也保证小Q只有一个。
小写字母a
-z
表示分别表示不同的传送阵,数据保证传送阵
两两配对。
Output
每组数据输出一行,解救小Q所需的最少步数,如果无论如何都 无法救小Q,输出-1
。
Sample input and output
Sample Input | Sample Output |
---|---|
2 5 5 ....L .###. b#b#a ##.## ...Qa 5 5 ....L .###. .#.#. ##.## ...Q. |
3 -1 |
处理,在输入的时候就将传送门的对应关系建立好。另外需要注意的是,在传送时,只能将传送门的一头标记为已访问,因为可能最短路是从另一头
传送过来的(传送门是双向的)。
好了,废话少说,献上代码。
#include<iostream> #include<queue> #include<string.h> #define MAX_N 50 #define MAX_M 50 #define INF 3000 using namespace std; typedef pair<int, int> P; char maze[MAX_N + 5][MAX_M + 5];//迷宫 int d[MAX_N + 5][MAX_M + 5];//表示离起点的距离 int dx[4] = { 0, 1, 0, -1 }; int dy[4] = { 1, 0, -1, 0 }; P door[MAX_N + 5][MAX_M + 5];//储存传送门的对应关系 bool flag[MAX_N + 5][MAX_M + 5];//记录节点是否被访问过 int lx, ly, qx, qy; int N, M; void input() { P temp[28]; cin >> N >> M; fill(temp, temp + 28, P(INF, INF)); for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) door[i][j].first = door[i][j].second = INF; for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) { char m; cin >> m; maze[i][j] = m; if (m >= 'a' && m <= 'z') { if (temp[m - 'a'] == P(INF, INF))//传送门第一次出现 temp[m - 'a'] = P(i, j); else//传送门已经出现过了 { door[i][j] = P(temp[m - 'a'].first, temp[m - 'a'].second); door[temp[m - 'a'].first][temp[m - 'a'].second] = P(i, j); } } else if (m == 'L'){lx = i; ly = j; maze[i][j] = '#';} else if (m == 'Q'){ qx = i; qy = j; } } } int bfs() { memset(flag, 0, sizeof(flag)); for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) d[i][j] = INF; queue<P> que; que.push(P(lx, ly));//将起点加入队列 d[lx][ly] = 0;//并将起点的距离赋为0 while (!que.empty())//不断循环,知道队列为空 { int nx, ny; P now = que.front();//当前节点 que.pop(); if (now.first == qx&&now.second == qy) break; for (int i = 0; i < 4; i++)//向四个方向遍历 { nx = now.first + dx[i]; ny = now.second + dy[i]; if (nx < N && nx >= 0 && ny < M && ny >= 0 && !flag[nx][ny])//未超边界,且未访问过 { if (maze[nx][ny] <= 'z'&&maze[nx][ny] >= 'a')//传送门 { int dnow = d[now.first][now.second]; d[door[nx][ny].first][door[nx][ny].second] = dnow + 1;//传送 que.push(P(door[nx][ny].first, door[nx][ny].second));//将传送后的节点加入队列 } else if (maze[nx][ny] != '#')//不是传送门 { d[nx][ny] = d[now.first][now.second] + 1; que.push(P(nx, ny)); } flag[nx][ny] = 1;//将节点标记为访问过 } } } return d[qx][qy]; } int main() { int T; cin >> T; for (int t = 0; t < T; t++) { input(); int res = bfs(); cout << (res == INF ? -1 : res); if (t < T - 1) cout << endl; } return 0; }