백준 문제 링크 : 20158 - 사장님 달려가고 있습니다
알바 첫날인 정훈이는 늦잠을 잤다. 다행히도 정훈이는 달리기가 정말 빨라서 괜찮다고 생각했지만, 오늘은 공사로 인해 길을 통제하는 중이었다. 첫날부터 늦을 수 없는 정훈이는 가장 빠른 경로를 생각하며 달린다.
공사로 인해 통제하는 구역은 N x N 지도에 통제 시작시각이 초 단위로 주어지며 통제를 시작하기 전까지만 그 구역을 들어갈 수 있다. 통제 시작시각과 그 구역에 도착시각이 같은 시간일 경우에는 구역에 들어갈 수 없다.
정수 N (1 ≤ N ≤ 100)이 주어진다.
둘째 줄부터 N개의 줄에 공사 지도의 정보가 주어진다. 지도에는 각 구역 통제 시작 시각 X (0 ≤ X ≤ 100)이 정수로 주어진다. X가 0이라면 통제를 하지 않는다.
정훈이가 (N, N)에 도착할 수 있는 최소 시간을 출력한다.
(N, N)에 도착할 수 없다면 "Fired"를 출력한다.

너비우선탐색(BFS)로 도착지점까지 갈 수 있는 최소 시간을 구하는 문제입니다.
다만 신경써야 할 조건들이 좀 까다롭습니다
문제에서는 (1, 1)을 시작 지점으로, (N, N)을 끝 지점으로 하고있지만 저는 (0, 0)을 시작 지점으로 삼았습니다.
문제에서 예제 입력 3에 대해 친절한 설명도 함께 덧붙여있는데, 눈 여겨 보아야 할 점은
따라서 현재 t초가 지났다고 하면, -> ((어떤 좌표의 통제 시작 시간) <= t) 인 경우에는 지나갈 수 없습니다.
a, prevK 대신에 속도 dx dy를 구조체에 포함시키고 이동방향에 따라 변화하도록 해봤지만 복잡하고 완벽히 구현되지 않는 것 같아 바꿨습니다.
또한 해당 좌표에 방문했는지 확인하는 visited 배열은 4차원 배열로 선언하며, 좌표와 방향, 가속도를 모두 확인합니다. (현재 좌표에, 현재 방향에서 현재의 가속도로 방문한 적 있는지 확인)
방향과 가속도 또한 확인하는 것이 다음과 같은 반례에서 중요합니다 :
6
0 1 1 1 1 1
0 1 1 1 1 1
0 1 1 1 1 1
0 1 1 1 1 1
0 1 1 1 1 1
0 0 0 0 0 0
이 경우 다음과 같이 이동하게 됩니다 :
(0,0) -> (1,0) -> (3,0) -> (2,0) -> (3,0) -> (5,0) -> (5,1) -> (5,3) -> (5,2) -> (5,3) -> (5,5)
처음 (3,0)에 도달했을 때, 아래쪽으로 한번 더 가려면 지도를 벗어나게 됩니다 (3칸 이동하게 됨)
따라서 (2,0)으로 한번 물러났다가, 다시 (3,0) -> (5,0)
오른쪽으로 가는 경우 또한 이와 같은 과정이 되며, 이 경우 답은 10입니다
방향과 가속도까지 포함하여 방문여부를 확인해야 이러한 경우를 처리할 수 있습니다
다음으로 가게 될 좌표인 ni, nj에 대해, 해당 좌표까지 가는게 가능한지는 bool값을 반환하는 함수(canGO)를 두어 확인하도록 했습니다. 이 함수에서는 (ni, nj)가 지도를 벗어나는지, 또는 방문했는지의 여부와 함께, 해당 좌표까지 가는 도중 혹여 통제가 시작된 좌표가 있지는 않은지 확인합니다. 방향에 따라 조건문을 4개를 넣었는데, for문으로 한번에 작성할 수 있을 것 같지만 그러지 않은 것은 당장 이렇게 쓰는게 편해서도 있지만 그냥 실력부족입니다.
전체적인 정리를 한번 하자면 다음과 같습니다.
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
typedef struct info {
int i, j, t, a, prevK;
}info; //좌표 i, 좌표 j, 경과시간 t, 가속도 a, 이전에 이동했던 방향 prevK
int map[101][101];
bool visited[101][101][4][101]; //좌표, 방향, 가속도
int minT = -1;
int di[4] = {1, 0, -1, 0};
int dj[4] = {0, 1, 0, -1};
bool canGo(int ni, int nj, info curInfo, int n, int k) {
if (ni < 0 || nj < 0 || ni >= n || nj >= n || visited[ni][nj][k][curInfo.a]) return false; //다음 위치가 지도범위를 넘어가는지 확인
//또한, (ni, nj)로 가는 과정에서, 이미 통제가 시작된 구역이 포함되어있으면 갈 수 없음.
if (ni - curInfo.i > 0) {
for (int curi = curInfo.i, curj = curInfo.j; curi <= ni; curi++) {
if (map[curi][curj] != 0 && map[curi][curj] <= curInfo.t) return false;
}
}
if (ni - curInfo.i < 0) {
for (int curi = curInfo.i, curj = curInfo.j; curi >= ni; curi--) {
if (map[curi][curj] != 0 && map[curi][curj] <= curInfo.t) return false;
}
}
if (nj - curInfo.j > 0) {
for (int curi = curInfo.i, curj = curInfo.j; curj <= nj; curj++) {
if (map[curi][curj] != 0 && map[curi][curj] <= curInfo.t) return false;
}
}
if (nj - curInfo.j < 0) {
for (int curi = curInfo.i, curj = curInfo.j; curj >= nj; curj--) {
if (map[curi][curj] != 0 && map[curi][curj] <= curInfo.t) return false;
}
}
return true;
}
void bfs(int n) {
queue<info>q;
q.push({0,0,0,1,-1});
visited[0][0][1][1] = true;
while (q.size()) {
info curInfo = q.front();
q.pop();
int i = curInfo.i;
int j = curInfo.j;
if (i == n-1 && j == n-1) {
if (minT == -1 || minT > curInfo.t) minT = curInfo.t;
continue;
}
for(int k=0;k<4;k++) {
int ni = i + di[k], nj = j + dj[k];
if (curInfo.prevK == k) {
ni = i + di[k] * (curInfo.a+1);
nj = j + dj[k] * (curInfo.a+1);
} //이전과 같은 방향으로 움직이려는 경우 더 간다
if (canGo(ni, nj, curInfo, n, k)) {
if (curInfo.prevK == -1) {
info p = {ni, nj, curInfo.t+1, 1, k};
q.push(p);
visited[ni][nj][k][1] = true;
}
else {
info p = {ni, nj, curInfo.t+1, 1, k};
if (curInfo.prevK == k) {
p.a = curInfo.a + 1;
} //prevK와 k가 같을 경우 같은 방향으로 이동하게 된 경우임 => 가속도 증가
q.push(p);
visited[ni][nj][k][p.a] = true;
}
}
}
}
}
int main () {
ios_base::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
cin >> map[i][j];
}
}
bfs(n);
if (minT == -1) cout << "Fired";
else cout << minT;
}
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣶⣾⣿⣿⣿⣿⣶⣦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⣰⣿⠿⠟⠿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠹⣷⡀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣼⠏⠀⠀⠀⠀⠈⢻⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠘⣷⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣼⠏⠀⠀⢀⣀⠀⠀⠀⣿⣿⣿⣿⠁⠀⠀⣤⣦⠀⠀⠀⠀⢹⣇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢠⣿⠀⠀⠀⠸⠟⠀⠀⠀⢸⣿⣿⡏⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⢀⣤⣼⠿⠿⠷⠶⢶⣄⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣾⡇⠀⠀⠀⠀⠀⠀⢿⣯⣤⣤⣴⣶⠶⠟⠋⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠸⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀