백조의 호수(BFS 최적화)
2022. 8. 31. 17:39ㆍC++/알고리즘
- BFS를 사용하는 문제지만 매번 BFS를 처음부터 진행하면 TimeLimit 발생.
- BFS를 사용하면서 갔던 노드에는 재방문하지 않도록 최적화가 필요한 문제.
- 물, 백조 각각 큐를 만들어서 각각 BFS를 진행.
- 백조 BFS의 초기값은 두 백조 중 하나의 좌표
- 백조 BFS에서 도달한 X 좌표들은 다음번 백조 BFS를 시작할 위치들임.
- 2차원 bool 배열을 만들어서 백조 BFS에서 방문했던 위치에 대해 따로 기록하고 이미 방문한 좌표는 탐색하지 않음.
- 백조 BFS에서 백조에 도달하면 반복문을 멈추고 해당 카운트값을 리턴.
- 물 BFS의 초기값은 입력받았던 .(물)과 L(백조)의 모든 좌표
- 물 BFS에서 도달한 X 좌표들은 .(물)로 바꿔주고 다음번 물 BFS를 시작할 위치들임.
- 물 BFS는 X 좌표에 대해서만 Enqueue를 진행하므로 따로 Visit 배열을 사용할 필요가 없음.
- 백조 BFS와 물 BFS를 한 번씩 진행했다면 도달했던 X좌표의 값을 저장한 NextQueue를 사용하여 BFS를 반복
- 2차원 배열 3개로 구현했지만 못풀었고 구글링으로 BFS 최적화 정보 찾은후 작성하여서 통과.
#include<iostream>
#include<queue>
using namespace std;
int row, column;
char space[1500][1500] = { 0, };
bool visit[1500][1500] = { 0, };
int dx[] = { 0, 0, 1, -1 };
int dy[] = { 1, -1, 0, 0 };
pair<int, int> Swan(-1, -1);
queue<pair<int, int>> WaterQ;
queue<pair<int, int>> WaterNQ;
queue<pair<int, int>> SwanQ;
queue<pair<int, int>> SwanNQ;
bool found = false;
void SwanBFS()
{
while (!SwanQ.empty())
{
int x = SwanQ.front().first;
int y = SwanQ.front().second;
SwanQ.pop();
for (int i = 0; i < 4; i++)
{
if (0 <= x + dx[i] && x + dx[i] < row && 0 <= y + dy[i] && y + dy[i] < column)
{
if (visit[x + dx[i]][y + dy[i]] == false)
{
visit[x + dx[i]][y + dy[i]] = true;
if (space[x + dx[i]][y + dy[i]] == 'L')
{
found = true;
break;
}
else if (space[x + dx[i]][y + dy[i]] == 'X')
{
SwanNQ.push(pair<int, int>(x + dx[i], y + dy[i]));
}
else if (space[x + dx[i]][y + dy[i]] == '.')
{
SwanQ.push(pair<int, int>(x + dx[i], y + dy[i]));
}
}
}
}
}
}
void WaterBFS()
{
while (!WaterQ.empty())
{
int x = WaterQ.front().first;
int y = WaterQ.front().second;
WaterQ.pop();
for (int i = 0; i < 4; i++)
{
if (0 <= x + dx[i] && x + dx[i] < row && 0 <= y + dy[i] && y + dy[i] < column)
{
if (space[x + dx[i]][y + dy[i]] == 'X')
{
space[x + dx[i]][y + dy[i]] = '.';
WaterNQ.push(pair<int, int>(x + dx[i], y + dy[i]));
}
}
}
}
}
int BFS()
{
// 물queue, 백조queue 2가지를 이용
// 물과 백조에 대하여 각각 BFS 진행
// 백조 BFS에서 도달한 X 좌표는 다음 백조 BFS를 시작할 위치
// 물 BFS로 도달한 X 좌표들은 다음 차례에 녹을 얼음들임
// 해당 얼음 좌표를 물의 next_queue에 삽입
// 현재 BFS 진행중인 queue가 모두 비워지면 next_queue로 BFS 진행
// 큐를 옮기는 해당 과정을 카운트해서 백조 BFS중 백조를 만나게 되면 그 카운트가 답
int count = 0;
while (!(WaterQ.empty() && SwanQ.empty()))
{
SwanBFS();
if (found) break;
WaterBFS();
count++;
SwanQ = SwanNQ;
SwanNQ = queue<pair<int, int>>();
WaterQ = WaterNQ;
WaterNQ = queue<pair<int, int>>();
}
cout << count << endl;
return count;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> row >> column;
for (int r = 0; r < row; r++)
{
for (int c = 0; c < column; c++)
{
cin >> space[r][c];
if (space[r][c] != 'X')
{
WaterQ.push(pair<int, int>(r, c));
}
if (space[r][c] == 'L')
{
Swan.first = r;
Swan.second = c;
}
}
}
SwanQ.push(Swan);
visit[Swan.first][Swan.second] = true;
BFS();
}
백준 3197번 문제(https://www.acmicpc.net/problem/3197)
'C++ > 알고리즘' 카테고리의 다른 글
컵라면(그리디 알고리즘) (1) | 2022.10.04 |
---|---|
라면 사기(그리디 알고리즘) (0) | 2022.10.04 |
우선순위 큐(Priority Queue) (0) | 2022.08.30 |
다이나믹 프로그래밍 (0) | 2022.08.29 |
최소신장트리(MST) (0) | 2022.08.28 |