문제 풀이
(1, 1) 시작점에서 (n, n) 도착점에 도착하기 위해서 몇 번의 검은 방을 부셔야 하는지 최소의 횟수를 구하는 문제다.
단순히 BFS 알고리즘을 돌리기에는 에러가 있다.
(3, 3) 의 좌표를 보자.
단순히 BFS를 돌리게 되면 (3,3)은 이전의 (2,3)이나 (3,2)로부터 부신 횟수에 + 1을 하여서 2가 될 수 있지만,
그림을 보면 (3,3)도 1번만 부셔서 갈 수 있는 곳이 된다.
기존에 방문을 했더라도 더 빠른 경로가 있다면 그 경로로 값을 바꿔주거나 갱신을 시켜줘야 한다는 것이다.
만약 내 앞의 방이 흰방이면, 방문을 했더라도 더 빠른 경로라면 더 빠른 경로로 갱신하고 다시 살펴본다.
만약 내 앞의 방이 검은방이면, 방문을 했더라도 더 빠른 경로라면 더 빠른 경로로 갱신하고 다시 살펴본다.
이미 방문을 했더라도 더 빠른 경로로 계속 갱신하면서 출구를 찾아나간다.
단순한 BFS의 프레임에서 벗어난 새로운 방법의 문제였다.
소스 코드
#include <iostream>
#include <queue>
#include <string>
#include <algorithm>
using namespace std;
const int MAX = 51;
const int INF = 987654321;
const int dx[] = { -1,1,0,0 };
const int dy[] = { 0,0,-1,1 };
int n;
int board[MAX][MAX];
int visit[MAX][MAX]; // visit[a][b] = c, (a,b) 까지 오는데 검은방을 흰방으로 바꾼 갯수가 c개
// 핵심은 이미 방문한 좌표라도 더 적은 경로가 있다면 재방문하는 것
void bfs()
{
fill(visit[0], visit[0] + MAX * MAX, INF);
queue<pair<int, int> > q;
q.push({ 0,0 });
visit[0][0] = 0;
while (!q.empty())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
// 흰방
if (board[nx][ny] == 1)
{
if (visit[nx][ny] > visit[x][y])
{
visit[nx][ny] = visit[x][y];
q.push({ nx,ny });
}
}
// 검은방이면 부수고 지나갈때
else
{
if (visit[nx][ny] > visit[x][y] + 1)
{
visit[nx][ny] = visit[x][y] + 1;
q.push({ nx,ny });
}
}
}
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for (int i = 0; i < n; i++)
{
string str;
cin >> str;
for (int j = 0; j < str.length(); j++)
{
board[i][j] = str[j] - '0';
}
}
bfs();
cout << visit[n - 1][n - 1] << endl;
return 0;
}
'Algorithm' 카테고리의 다른 글
[백준 3036] 링 (0) | 2021.11.09 |
---|---|
[백준 1037] 약수 (0) | 2021.11.09 |
[백준 14221] 편의점 (0) | 2021.11.04 |
[백준 18352] 특정 거리의 도시 찾기 (0) | 2021.11.04 |
[백준 10282] 해킹 (0) | 2021.10.31 |