计蒜客题解——T1213:拯救行动
題目相關(guān)
題目鏈接
計(jì)蒜客 OJ,https://nanti.jisuanke.com/t/T1213。
題目描述
公主被惡人抓走,被關(guān)押在牢房的某個地方。牢房用 N×M(N,M≤200) 的矩陣來表示。矩陣中的每項(xiàng)可以代表道路(@)、墻壁(#)、和守衛(wèi)(x)。
英勇的騎士(r)決定孤身一人去拯救公主(a)。我們假設(shè)拯救成功的表示是 "騎士到達(dá)了公主所在的位置"。由于在通往公主所在位置的道路中可能遇到守衛(wèi),騎士一旦遇到守衛(wèi),必須殺死守衛(wèi)才能繼續(xù)前進(jìn)。
現(xiàn)假設(shè)騎士可以向上、下、左、右四個方向移動,每移動一個位置需要 1 個單位時間,殺死一個守衛(wèi)需要花費(fèi)額外的 1 個單位時間。同時假設(shè)騎士足夠強(qiáng)壯,有能力殺死所有的守衛(wèi)。
給定牢房矩陣,公主、騎士和守衛(wèi)在矩陣中的位置,請你計(jì)算拯救行動成功需要花費(fèi)最短時間。
輸入格式
1、兩個整數(shù)代表 N 和 M,(N,M≤200).
2、隨后 N 行,每行有 M 個字符。"@" 代表道路,"a" 代表公主,"r" 代表騎士,"x" 代表守衛(wèi), "#" 代表墻壁。
輸出格式
如果拯救行動成功,輸出一個整數(shù),表示行動的最短時間。
如果不可能成功,輸出 "Impossible"。
樣例輸入1
7 8 #@#####@ #@a#@@r@ #@@#x@@@ @@#@@#@# #@@@##@@ @#@@@@@@ @@@@@@@@樣例輸出1
13樣例輸入2
13 40 @x@@##x@#x@x#xxxx##@#x@x@@#x#@#x#@@x@#@x xx###x@x#@@##xx@@@#@x@@#x@xxx@@#x@#x@@x@ #@x#@x#x#@@##@@x#@xx#xxx@@x##@@@#@x@@x@x @##x@@@x#xx#@@#xxxx#@@x@x@#@x@@@x@#@#x@# @#xxxxx##@@x##x@xxx@@#x@x####@@@x#x##@#@ #xxx#@#x##xxxx@@#xx@@@x@xxx#@#xxx@x##### #x@xxxx#@x@@@@##@x#xx#xxx@#xx#@#####x#@x xx##@#@x##x##x#@x#@a#xx@##@#@##xx@#@@x@x x#x#@x@#x#@##@xrx@x#xxxx@##x##xx#@#x@xx@ #x@@#@###x##x@x#@@#@@x@x@@xx@@@@##@@x@@x x#xx@x###@xxx#@#x#@@###@#@##@x#@x@#@@#@@ #@#x@x#x#x###@x@@xxx####x@x##@x####xx#@x #x#@x#x######@@#x@#xxxx#xx@@@#xx#x#####@樣例輸出2
7題目分析
題意分析
一個 N*M 大小的迷宮,我們從 r 位置出發(fā)(也就是起點(diǎn)),字符 @ 表示可以安全通行的方格,字符 # 表示墻壁(也就是不能走),字符 x 代表守衛(wèi)(守衛(wèi)可以殺死,但是必須付出額外的 1 個單位時間),字符 a 表示仙藥(也就是終點(diǎn))。要求輸出從 @ 到 a 的最短路徑。那么迷宮問題的基本要素全齊了,所以本題就是一道 BFS 模板題。
樣例數(shù)據(jù)分析
本題和以前的 BFS 模板題唯一的不同就是所有守衛(wèi)可以殺死,但是需要付出額外的時間。因此意味著 x 的地方是可以走的,只是要多付出 1 個單位時間。也就是說,走 x 地方,需要 2 個時間單位;走 @ 地方,需要 1 個時間單位。
省略。如果想看類似的數(shù)據(jù)分析,可以看以前的文章,https://blog.csdn.net/justidle/article/details/104651311。主要是我偷懶了,畫圖太累了,請?jiān)彙?/p>
算法思路
1、讀入數(shù)據(jù),并寫入到合適的數(shù)據(jù)結(jié)構(gòu)中。
2、找到起點(diǎn)位置,將起點(diǎn)加入到隊(duì)列 q 中。
3、記錄終點(diǎn)位置信息。
4、開始 BFS 遍歷。直到找到終點(diǎn)或者遍歷所有節(jié)點(diǎn)而無法到達(dá)終點(diǎn)。注意:走 x 地方,需要 2 個時間單位;走 @ 地方,需要 1 個時間單位。
AC 參考代碼
#include <cstdio> #include <queue>//位置定義 struct POS {int x, y;//坐標(biāo)int cost;//本節(jié)點(diǎn)到起點(diǎn)的距離 };const int MAXN = 202; struct MAZE {int row, col;//迷宮大小char data[MAXN][MAXN];//迷宮數(shù)據(jù)描述bool visit[MAXN][MAXN];//是否已經(jīng)訪問過節(jié)點(diǎn)int x1, y1;//起點(diǎn)坐標(biāo)int x2, y2;//終點(diǎn)坐標(biāo) };int bfs(MAZE &maze);int main() {MAZE maze = {};//迷宮定義并將所有初始化為零//讀入迷宮長寬 scanf("%d %d", &maze.row, &maze.col);//讀入迷宮數(shù)據(jù)int i,j;for (i=0; i<maze.row; i++) {for (j=0; j<maze.col; j++) {scanf(" %c", &maze.data[i][j]);if (maze.data[i][j]=='a') {//終點(diǎn)maze.x2 = i;maze.y2 = j; } else if (maze.data[i][j]=='r') {//起點(diǎn)maze.x1 = i;maze.y1 = j; }}} int ans = bfs(maze);if (ans>0) {printf("%d\n", ans);} else {printf("Impossible\n");}return 0; }int bfs(MAZE &maze) {std::queue<POS> q;//下一個節(jié)點(diǎn)隊(duì)列const POS move[] = {{-1,0}, {0,1}, {1,0}, {0,-1}};//騎士的移動方法POS cur;//當(dāng)前位置POS next;//下一個位置//加入起點(diǎn)cur.x = maze.x1;cur.y = maze.y1;cur.cost = 0;maze.visit[cur.x][cur.y] = true;//設(shè)置本節(jié)點(diǎn)已經(jīng)訪問q.push(cur); //開始遍歷while (!q.empty()) {//彈出隊(duì)首節(jié)點(diǎn)cur = q.front();q.pop();if (maze.data[cur.x][cur.y]=='x') {//由于有干掉守衛(wèi),所以我們我們先加入的不一定是最小的maze.data[cur.x][cur.y]='@';cur.cost++;q.push(cur);} else {for (int i=0; i<4; i++) {next.x = cur.x + move[i].x;next.y = cur.y + move[i].y;//判斷是不是終點(diǎn)if (next.x==maze.x2 && next.y==maze.y2) {return cur.cost + 1;} //判斷通過性if (next.x>=0&&next.x<maze.row&&next.y>=0&&next.y<maze.col&&maze.visit[next.x][next.y]==false&&maze.data[next.x][next.y]!='#') {next.cost = cur.cost + 1;maze.visit[next.x][next.y] = true;q.push(next);}}}}return -1; }代碼分析
1、如何表示一個節(jié)點(diǎn)的坐標(biāo),以及該節(jié)點(diǎn)到起點(diǎn)的距離。這里我用一個自定義的結(jié)構(gòu)體來表示。如下所示:
struct POS {int x, y;//當(dāng)前結(jié)點(diǎn)坐標(biāo)int cost;//從起點(diǎn)到當(dāng)前結(jié)點(diǎn)的距離 };2、如何表示一個迷宮。這里我將所有迷宮信息全部放在一個自定義結(jié)構(gòu)體中,增強(qiáng)了代碼可讀性。如下所示:
const int MAXN = 200; struct MAZE {int m, n;//迷宮大小char data[MAXN][MAXN];//迷宮的數(shù)據(jù)bool visit[MAXN][MAXN];//是否已經(jīng)走過int x1, y1;//起點(diǎn)信息int x2, y2;//終點(diǎn)信息 };3、如何表示所有移動可能性。如下所示:
const POS move[] = {{-1,0}, {0,1}, {1,0}, {0,-1}};//定義移動方法4、新節(jié)點(diǎn)通過性判斷問題。根據(jù)題目進(jìn)行判斷,基本包括以下幾個方面:
(1)這個位置可以走,如本題中用字符 . 表示。如下所示:
maze.data[next.x][next.y]!='#'注意,只要不是 # 就認(rèn)為這個節(jié)點(diǎn)是可以走的。至于是否是守衛(wèi),我們等彈出的時候再判斷。這個細(xì)節(jié)是和標(biāo)準(zhǔn)走迷宮不一樣的。
(2)這個位置沒有訪問過。如下所示:
maze.visit[next.x][next.y]==false(3)這個位置處于迷宮內(nèi)。這個判斷和您程序?qū)γ詫m定義有關(guān)。如下所示:
next.x>=0&&next.x<maze.m&&next.y>=0&&next.y<maze.n(4)判斷這個位置是不是守衛(wèi)。在彈出隊(duì)首元素的時候才判斷。如下所示:
if (maze.data[cur.x][cur.y]=='x') {//由于有干掉守衛(wèi),所以我們我們先加入的不一定是最小的maze.data[cur.x][cur.y]='@';cur.cost++;q.push(cur); }當(dāng)然,也可以在走到本位置的時候進(jìn)行判斷。不管在哪里判斷,是不會影響結(jié)果的,這是由于 BFS 的特性決定的。
總結(jié)
以上是生活随笔為你收集整理的计蒜客题解——T1213:拯救行动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习~模糊神经网络(FNN)
- 下一篇: 使用SAS创建日历表