第一行為 T,表示輸入數據組數。下面 T 組數據,對于每組數據:第一行是兩個數字 n, m(2 < n * m <= 64),表示迷宮的長與寬。接下來 n 行,每行 m 個字符,‘.’表示空地可以通過,‘x’表示陷阱,‘*’表示機關,‘S’代表起點,‘E’代表出口,‘K’表示鑰匙(保證存在且只有一個)。
Output
對第 i 組數據,輸出Case #i:然后輸出一行,僅包含一個整數,表示最少多少步能夠拿到鑰匙并走出迷魂陣,如果不能則打出-1。
這道題有機關這個設定,可以用01表示每個位置是否翻轉,剛好地圖的大小最多是64,可以用一個unsigned long long表示,因為是求最少的步數所以BFS,剩下的就是判重,剛開始不會,看了網上的博客,都是用hash判重,感覺沒必要用hash,完全可以用set和map,當然這里需要注意,判重的結構體里面不應該存在步數(MLE),只要是這個狀態存在就跳過
讀入數據的時候記錄起點,key,終點的位置
bfs搜索,發現一個新的狀態,就加入queue和set中,直到找到終點且此時鑰匙已經找到
// set#include <iostream>#include <stdio.h>#include <map>#include <vector>#include <set>#include <queue>#include <cstring>#include <cmath>#include <algorithm>#define N 100005#define ll unsigned long longusingnamespacestd;
char a[70][70];
int kx, ky, ex, ey, sx, sy, n, m, ans;
struct ac{int x, y, step;ll pos;bool key;// set排序 需要指定規則booloperator <(const ac &a) const{if (a.x != x) return a.x < x;elseif (a.y != y) return a.y < y;// else if (a.step != step) return a.step < step;elseif (a.pos != pos) return a.pos < pos;elsereturn a.key < key;}
};
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
set<ac> st;
queue<ac> que;
bool judge(int x, int y) {if (x < 0 || y < 0 || x >= n || y >= m)returnfalse;returntrue;
}
void add(int x, int y, int step, ll pos, bool key) {ac t;t.x = x;t.y = y;t.pos = pos;t.key = key;// 當前狀態是否已經記錄if (st.find(t) != st.end()) {return;}st.insert(t);t.step = step;que.push(t);
}
// 觸發機關后改變四個方向的狀態
ll change(ll x, ll y, ll pos) {for (int i = 0; i < 4; ++i) {ll xx = x + dx[i];ll yy = y + dy[i];if (!judge(xx, yy)) continue;pos ^= 1ll << (xx * m + yy);}return pos;
}
void update(int x, int y, int step, ll pos, bool key) {if (!judge(x, y)) return;// 判斷當前位置是否翻轉bool flag = 1ll << (x * m + y) & pos;// 如果翻轉過而且原來是陷阱,現在就可以通過if (flag == true && a[x][y] == 'x') {// 加入隊列和setadd(x, y, step, pos, key);}// 如果沒有翻轉過,只要不是陷阱,就可以通過if (flag == false && a[x][y] != 'x') {if (x == kx && y == ky) {add(x, y, step, pos, true);}elseif (a[x][y] == '*') {// 觸發機關改變四個方向的狀態add(x, y, step, change(x, y, pos), key);}else {add(x, y, step, pos, key);}}
}void bfs() {ac t;t.x = sx;t.y = sy;t.pos = 0;t.key = false;// 清空set和queuewhile (!que.empty()) que.pop();st.clear();// set中沒有stepst.insert(t);t.step = 0;que.push(t);while (!que.empty()) {ac f = que.front();que.pop();// 如果找到鑰匙和出口,returnif (f.x == ex && f.y == ey && f.key) {ans = f.step;return;}// 向四個方向更新for (int i = 0; i < 4; ++i) {int x = f.x + dx[i];int y = f.y + dy[i];update(x, y, f.step + 1, f.pos, f.key);}}
}int main() {
#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);
#endifint t;int Case = 1;scanf("%d", &t);while (t--) {scanf("%d%d", &n, &m);for (int i = 0; i < n; ++i) {scanf("%s", a[i]);}// 讀入數據,記錄for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (a[i][j] == 'K') {kx = i;ky = j;a[i][j] = '.';}if (a[i][j] == 'S') {sx = i;sy = j;a[i][j] = '.';}if (a[i][j] == 'E') {ex = i;ey = j;a[i][j] = '.';}}}ans = -1;bfs();printf("Case #%d:\n%d\n", Case++, ans);}return0;
}
// hash#include <iostream>#include <stdio.h>#include <map>#include <vector>#include <set>#include <queue>#include <cstring>#include <cmath>#include <algorithm>#define N 10005#define ll unsigned long longusingnamespacestd;char a[64][64];
int sx, sy, kx, ky, ex, ey;
int n, m;
int ans;
int mod = 10000;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
bool judge(int x, int y) {if (x < 0 || y < 0 || x >= n || y >= m)returnfalse;elsereturntrue;
}
struct ac{int x, y, step;ll pos;bool key;int hash() {return (pos % mod + x + y + key) % mod;}booloperator ==(const ac & t) {return t.x == x && t.y == y && pos == t.pos && key == t.key;}
};
queue<ac> que;
vector<ac> Hash[N];
void add(int x, int y, int step, bool key, ll pos) {ac t;t.x = x, t.y = y, t.step = step, t.key = key, t.pos = pos;int idx = t.hash();for (int i = 0; i < Hash[idx].size(); ++i) {if (Hash[idx][i] == t)return;}Hash[idx].push_back(t);que.push(t);
}
ll change(int x, int y, ll pos) {for (int i = 0; i < 4; ++i) {int xx = x + dx[i];int yy = y + dy[i];if (judge(xx, yy) == false) continue;pos ^= 1ll << (xx * m + yy);}return pos;
}
void update (int x, int y, int step, bool key, ll pos) {bool flag = (1ll << (x * m + y)) & pos;if (a[x][y] == 'x' && flag) {add(x, y, step, key, pos);}elseif (a[x][y] != 'x' && flag == false) {if (x == kx && y == ky)add(x, y, step, true, pos);elseif (a[x][y] == '*')add(x, y, step, key, change(x, y, pos));elseadd(x, y, step, key, pos);}
}void bfs() {while (!que.empty()) que.pop();for (int i = 0; i < mod; ++i) {Hash[i].clear();}ac t;t.x = sx, t.y = sy, t.step = 0, t.key = false, t.pos = 0;Hash[t.hash()].push_back(t);que.push(t);while (!que.empty()) {ac f = que.front();que.pop();if (f.x == ex && f.y == ey && f.key == true) {ans = f.step;return;}for (int i = 0; i < 4; ++i) {int x = f.x + dx[i];int y = f.y + dy[i];if (judge(x, y) == false) continue;update(x, y, f.step + 1, f.key, f.pos);}}
}
int main() {
#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);
#endifint t, Case = 1;scanf("%d", &t);while (t--) {scanf("%d%d", &n, &m);for (int i = 0; i < n; ++i) {scanf("%s", a[i]);}for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (a[i][j] == 'K') {kx = i, ky = j;a[i][j] = '.';}if (a[i][j] == 'E') {ex = i, ey = j;a[i][j] = '.';}if (a[i][j] == 'S') {sx = i, sy = j;a[i][j] = '.';}}}ans = -1;bfs();printf("Case #%d:\n%d\n", Case++, ans);}return0;
}