Labyrinth
Labyrinth
أُعطيت خريطة لمتاهة، ومهمتك إيجاد مسار من البداية إلى النهاية. يمكنك المشي يساراً ويميناً وأعلى وأسفل.
المدخل:
السطر الأول: عددان صحيحان
nوm— الارتفاع والعرض.ثم
nأسطر: كل سطر يحتويmحرفاً:.أرضية#جدارAالبدايةBالنهاية
يوجد بالضبط حرفAواحد وحرفBواحد.
المخرجات:
اطبع
"YES"إذا كان هناك مسار، وإلا اطبع"NO".إذا كان هناك مسار، اطبع أيضاً:
- طول أقصر مسار
- سلسلة تصف المسار باستخدام
L, R, U, D
(أي أقصر مسار مقبول)
القيود:
1 ≤ n, m ≤ 1000
مثال:
المدخل:
5 8
########
#.A#...#
#.##.#B#
#......#
########
المخرجات:
YES
9
LDDRRRRRU
Solution
نحتاج أقصر مسار في شبكة غير موزونة (كل حركة تكلفتها 1). هذا بالضبط ما تعطيه BFS.
اعتبر كل خلية مفتوحة عقدة، وتوجد أحرف بين الخلايا المفتوحة المتجاورة (أعلى/أسفل/يسار/يمين). شغّل BFS من A، وخزّن من أين أتينا (أب + حركة)، ثم أعد بناء المسار عندما نصل إلى B.
فكرة BFS
نحافظ على:
dist[r][c]= المسافة منAإلى الخلية(r,c)(-1يعني غير مُزارة)parDir[r][c]= أي حركة استُخدمت للدخول إلى(r,c)من أبيها (واحدة منL,R,U,D)
BFS تستكشف الخلايا بترتيب مسافة متزايدة، لذا أول مرة نصل فيها إلى B تكون مضمونة أنها الأقصر.
إعادة بناء المسار
إذا كانت B قابلة للوصول، نرجع للخلف من B إلى A باستخدام parDir:
- إذا كانت
parDir[cur] == 'U'فهذا يعني أننا تحركنا للأعلى للوصول إلىcur، إذن الأب يقع صفاً واحداً للأسفل، وهكذا. - نجمع الحركات ثم نعكسها في النهاية.
الجواب النهائي
- إذا كانت
dist[B] == -1→ اطبعNO. - غير ذلك اطبع
YES، ثمdist[B]، ثم سلسلة الحركات المُعادة بناؤها.
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <utility>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<string> grid(n);
for (int i = 0; i < n; i++) cin >> grid[i];
pair<int,int> A{-1,-1}, B{-1,-1};
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 'A') A = {i, j};
if (grid[i][j] == 'B') B = {i, j};
}
}
vector<vector<int>> dist(n, vector<int>(m, -1));
vector<vector<char>> parDir(n, vector<char>(m, 0));
queue<pair<int,int>> q;
dist[A.first][A.second] = 0;
q.push(A);
// Directions: (dr, dc, moveChar)
const int dr[4] = {-1, 1, 0, 0};
const int dc[4] = {0, 0, -1, 1};
const char mv[4] = {'U', 'D', 'L', 'R'};
while (!q.empty()) {
auto [r, c] = q.front(); q.pop();
for (int k = 0; k < 4; k++) {
int nr = r + dr[k];
int nc = c + dc[k];
if (nr < 0 || nr >= n || nc < 0 || nc >= m) continue;
if (grid[nr][nc] == '#') continue;
if (dist[nr][nc] != -1) continue;
dist[nr][nc] = dist[r][c] + 1;
parDir[nr][nc] = mv[k];
q.push({nr, nc});
}
}
if (dist[B.first][B.second] == -1) {
cout << "NO\n";
return 0;
}
cout << "YES\n";
cout << dist[B.first][B.second] << "\n";
// Reconstruct path from B back to A
string path;
int r = B.first, c = B.second;
while (!(r == A.first && c == A.second)) {
char d = parDir[r][c];
path.push_back(d);
// Move to parent (reverse the move)
if (d == 'U') r += 1;
else if (d == 'D') r -= 1;
else if (d == 'L') c += 1;
else if (d == 'R') c -= 1;
}
reverse(path.begin(), path.end());
cout << path << "\n";
return 0;
}