N×M 迷宮(N,M≤100),'.' 空地,'#' 障礙。K 個機關(K≤10)須按順序觸發。起始位置給定。移動:可走 8 方向(含斜向),但不可跨過兩個障礙的夾縫(即斜向移動時,若相鄰兩格均為障礙則不可通過)。求觸發所有機關並離開的最少步數,不可達輸出 -1。
從 (x,y) 移動到 (nx,ny):
cnt = (g[x][ny]=='#') + (g[nx][y]=='#'),若 cnt >= 2 則不可通過。(x,y,step),訪問標記 vis[x][y]。#include <iostream>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int N, M, K;
char g[MAXN][MAXN];
bool vis[MAXN][MAXN];
int dr[8] = {-1,-1,-1,0,0,1,1,1};
int dc[8] = {-1,0,1,-1,1,-1,0,1};
struct Node { int r, c, d; };
bool valid(int r, int c) {
return r>=1 && r<=N && c>=1 && c<=M && !vis[r][c] && g[r][c]!='#';
}
bool can_move(int r, int c, int nr, int nc) {
if (abs(r-nr)+abs(c-nc) == 1) return true; // 直向
// 斜向:檢查兩側直向格
int cnt = 0;
if (g[r][nc] == '#') ++cnt;
if (g[nr][c] == '#') ++cnt;
return cnt < 2;
}
int bfs(int sr, int sc, int tr, int tc) {
if (sr==tr && sc==tc) return 0;
memset(vis, 0, sizeof(vis));
queue q;
q.push({sr, sc, 0});
vis[sr][sc] = true;
while (!q.empty()) {
Node u = q.front(); q.pop();
for (int i=0;i<8;++i) {
int nr=u.r+dr[i], nc=u.c+dc[i];
if (!valid(nr,nc) || !can_move(u.r,u.c,nr,nc)) continue;
if (nr==tr && nc==tc) return u.d+1;
vis[nr][nc] = true;
q.push({nr, nc, u.d+1});
}
}
return -INF;
}
int main() {
int T; cin >> T;
while (T--) {
cin >> N >> M >> K;
for (int i=1;i<=N;++i) cin >> (g[i]+1);
int sr, sc; cin >> sr >> sc;
vector> targets;
for (int i=0;i> r >> c;
targets.emplace_back(r,c);
g[r][c] = '@'; // 標記機關
}
int ans = 0;
bool ok = true;
for (auto [tr,tc] : targets) {
g[tr][tc] = '.'; // 觸發後變空地
int dist = bfs(sr, sc, tr, tc);
if (dist < 0) { ok = false; break; }
ans += dist;
sr = tr; sc = tc;
}
cout << (ok ? ans : -1) << '\n';
}
return 0;
}
g[tr][tc]='.',允許後續路徑經過。sr==tr && sc==tc 返回 0 步完美處理。can_move 只檢查水平/垂直相鄰兩格,不檢查對角對面格。ZZULIOJ 1726 是「多目標順序 BFS + 8方向移動 + 幾何通行約束」綜合題。關鍵點:
can_move。掌握「BFS + 動態障礙 + 移動約束」模板,可解決所有網格最短路變體。