[BOJ]伯俊4179号火!
リンク
https://www.acmicpc.net/problem/4179
質問する
志訓は迷宮で働いている.智勲を助けて迷宮を脱出せよ!
智勲の迷路での位置と点火された位置を考慮して、智勲が火に焼かれる前に脱出できるかどうか、そしてどれだけ速いスピードで脱出できるかを決めなければならない.
智勲と火は毎分水平または垂直に1格移動する(傾斜せずに移動する).
火は各点から4方向に拡散する.
ジフンは迷宮の端に近い空間から脱出できる.
智勲と火は壁のある空間を通ることができない.
入力
入力された最初の行には、スペースで区切られた2つの整数RとCが与えられます.ただし,1≦R,C≦1000であった.Rは迷宮行の個数,Cは列の個数である.
次の入力では、R行にそれぞれ迷路行が与えられる.
各文字の意味は次のとおりです.
#:壁
.:通過可能な空間
J:ジフンの迷宮での初期位置(通過可能な空間)
F:発火する空間
Jは入力に1つだけ与えられる.
しゅつりょく
智勲が火が到着するまで迷宮を脱出できなければ、IMPOSIBLEを出力する.
智勲が迷宮から脱出できれば、最も速い脱出時間を出力する.
に答える
#include <iostream>
#include <string>
#include <stack>
#include <queue>
#define X first
#define Y second
using namespace std;
int r, c;
string board[1001];
int dist1[1001][1001]; //불의 전파 시간
int dist2[1001][1001]; //J의 이동시간
int dx[4] = { 0, 1, 0, -1 };
int dy[4] = { 1, 0, -1, 0 };
int main(void) {
//먼저 불이 지나가는 bfs 구하고 J가 가는 길 bfs를 구한다.
ios::sync_with_stdio(0);
cin.tie(0);
cin >> r >> c;
for (int i = 0; i < r; i++) { //모든 dist -1로 초기화
fill(dist1[i], dist1[i] + c, -1);
fill(dist2[i], dist2[i] + c, -1);
}
for (int i = 0; i < r; i++) {
cin >> board[i];
}
queue <pair<int, int>> q1;
queue <pair<int, int>> q2;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (board[i][j] == 'F') { //불을 먼저 푸시
q1.push({ i, j });
dist1[i][j] = 0;
}
if (board[i][j] == 'J') { //불을 먼저 푸시
q2.push({ i, j });
dist2[i][j] = 0;
}
}
}
//불에 대한 bfs
while (!q1.empty()) {
pair <int, int > cur = q1.front();
q1.pop();
for (int dir = 0; dir < 4; dir++) {
int nx = cur.X + dx[dir];
int ny = cur.Y + dy[dir];
if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
if (dist1[nx][ny] >= 0 || board[nx][ny] == '#') continue;
dist1[nx][ny] = dist1[cur.X][cur.Y] + 1;
q1.push({ nx, ny });
}
}
//J에 대한 bfs
while (!q2.empty()) {
pair <int, int> cur = q2.front();
q2.pop();
for (int dir = 0; dir < 4; dir++) {
int nx = cur.X + dx[dir];
int ny = cur.Y + dy[dir];
if (nx < 0 || nx >= r || ny <0 || ny >= c) { // 범위를 넘긴다는 것은 곧 탈출에 성공했다는 의미. 큐에 반드시 거리순으로 들어가므로 최초에 탈출한 시간을 입력하면 됨.
cout << dist2[cur.X][cur.Y] + 1;
return 0;
}
if (dist2[nx][ny] >= 0 || board[nx][ny] == '#') continue;
if (dist1[nx][ny] != -1 && dist1[nx][ny] <= dist2[cur.X][cur.Y] + 1) continue;
//해당 칸에 J가 가는 최소 시간이 불길이 닿는 시간보다 같거나 크면 해당 칸에 갈 수 없다. 불의 전파 시간을 조건에 추가.
dist2[nx][ny] = dist2[cur.X][cur.Y] + 1;
q2.push({ nx, ny });
}
}
cout << "IMPOSSIBLE"; // 여기에 도달했다는 것은 탈출에 실패를 의미.
}
説明:
👨🏻🏫 対火のbfsと対智勲のbfsは別々に解決できる.まずbfsによる火の伝搬を迂回し,各格子における火の伝搬時間を事前に求めた.そして智勲はbfsを求め、Jが行く最小時間が炎が到着する時間以上であれば、この格子に行くことはできない.火の伝播時間を条件に加えなければならない.
これまでbfsの目的地が決まっていたり、他に行く場所がなかったりしたとき、ずっと回っていたのに対して、今回は外郭に逃げます.範囲を超えたのは、すぐに脱出に成功したことを意味します.キューは距離順に入る必要があるので、最初に脱出した時間を入力して戻ります.
📌 智勲は火の影響を受けているが、火の伝播は智勲の影響を受けないので、まず不満を伝播させることは可能だ.しかし,Bが相互に影響する場合,どちらか一方を最後まで伝播することは不可能である.AとBを時間順に同時に行います.
Reference
この問題について([BOJ]伯俊4179号火!), 我々は、より多くの情報をここで見つけました https://velog.io/@dnflrhkddyd/BOJ-백준-4179번-불テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol