Saving Tang Monk
問題分析
本題就是屬於拿鑰匙去開門的 類題目。
題意:孫悟空必須拿到 個鑰匙才能救出唐僧,但是期間如果遇到蛇怪需要多花一分鐘去打敗她們,並且在拿到第 個鑰匙之前必須先拿到第 個鑰匙,問最少的花費時間。
這題就麻煩在三個地方,
一、同種鑰匙可能有多個,拿完鑰匙的地方仍然可以走,所以需要加一維鑰匙的狀態來判重。
二、因爲打敗蛇怪需要多花費時間,所以肯定要優先走不經過蛇怪的最短路,優先隊列解決。
三、打過蛇怪的地方仍然可以走動,所以需要判斷蛇洞裏的蛇怪 沒有,所以需要節點加一個打蛇怪的狀態 。就比如用 給蛇編號的,判斷 號蛇怪是否死亡就用當前的狀態 ,如果結果等於0則說明i蛇怪還沒有 ,否則就是 。
#include <bits/stdc++.h>
struct node {
int x, y, step, snake, key;
bool operator<(const node &u) const {
return step > u.step;
}
};
const int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
bool vis[111][111][11];
char a[111][111];
int n, m, snakeLoc[111][111];
int rec(int stx, int sty, int desx, int desy) {
std::priority_queue<node> pq;
node cur, nxt;
cur.x = stx, cur.y = sty, cur.step = cur.key = cur.snake = 0;
pq.push(cur);
while (!pq.empty()) {
cur = pq.top();
pq.pop();
if (cur.x == desx && cur.y == desy && cur.key == m)
return cur.step;
for (int i = 0; i < 4; ++i) {
int tx = cur.x + dir[i][0];
int ty = cur.y + dir[i][1];
int key = cur.key, step = cur.step + 1, snake = cur.snake;
if (a[tx][ty] == cur.key + '1')
key++;
if (tx < 0 || tx >= n || ty < 0 || ty >= n || vis[tx][ty][key] || a[tx][ty] == '#')
continue;
if (a[tx][ty] == 'S' && ((snake & (1 << snakeLoc[tx][ty])) == 0)) //if it is a alive snake
step++, snake |= (1 << snakeLoc[tx][ty]);
vis[tx][ty][key] = 1;
nxt = {tx, ty, step, snake, key};
pq.push(nxt);
}
}
return -1;
}
int main() {
while (~scanf("%d%d", &n, &m) && (n + m)) {
int stx, sty, desx, desy, cnt = 0;
memset(vis, 0, sizeof vis);
memset(snakeLoc, 0, sizeof(snakeLoc));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) {
scanf(" %c", &a[i][j]);
if (a[i][j] == 'K') stx = i, sty = j;
if (a[i][j] == 'T') desx = i, desy = j;
if (a[i][j] == 'S') snakeLoc[i][j] = cnt++;
}
int ans = rec(stx, sty, desx, desy);
if (ans == -1) puts("impossible");
else printf("%d\n", ans);
}
return 0;
}