티스토리 뷰
안녕하세요 !!! 우디😎입니다.
오늘은 BFS로 푼 구슬 탈출 2 문제에 대해 설명해드릴께요.
문제
문제 설명
< 이 문제의 KEY POINT >
- 최소 몇 번 만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 출력한다. 만약, 10번 이하로 움직여서 빨간 구슬을 구멍을 통해 빼낼 수 없으면 -1을 출력한다. ==> 10번 동안의 BFS
- 파란 구슬이 구멍에 들어가면 실패 , 기울이는 동작은 구슬의 움직임이 없을 때까지 기울임. (백준 예제 7번) ==> (빨간 구슬과 파란 구슬이 동시에 들어갈 수 있음)
😘 : 위의 KEY POINT 대로 차근차근 설명해드리겠습니다.
➊. 10번 동안의 BFS
빨간 구슬이 구멍을 찾아가기 위해서 상,하,좌,우 중 10개의 방향을 조합해서 찾을 수가 있습니다.
또한, 최적화 하여 한방에 ! 빨간 구슬이 구멍을 찾아갈 수 있을 까요 ??? 불가능 합니다.
따라서, 이 문제는 완전 탐색이 되겠습니다 !
구현 방법으로는 BFS가 적합한데 이유는 트리를 통해 설명해 드리겠습니다.
🌳 트리
위의 그림처럼 처음 시작을 상 하 좌 우 로 한 트리가 4가지가 나올 수 있습니다.
맨 왼쪽 상 방향을 시작으로 한 트리를 보자면 구슬이 상으로 움직인 다음 좌, 우로 움직인다고 되어있습니다.
여기서, 상으로 움직인 다음 상,하,좌,우로 움직일 수도 있지 않느냐 하실 수 있는데, 문제에서의 답은 구슬은 최소로 움직여야 합니다.
🎨따라서, 상으로 움직였는데 다시 상으로 움직일 필요는 없겠죠 ~
🎨또한, 하로 다시 움직여 버린다면 구슬이 제자리 걸음만 되는 격이니, 필요가 없습니다 ~
이처럼, 상으로 움직인 것을 좌, 우로 움직일 수 있고, 좌로 움직인 것은 다시 상,하 우로 움직인 것은 다시 상,하로 움직이는 등 트리에서 넓게 넓게 가로로 가로로(?) 탐색해주죠 ??
그래서, BFS로 풀면 됩니다 !!!
➋. 구슬의 이동
구슬의 이동
- 구슬 2개가 나란히 있을때, 먼저 이동시켜줘야 하는 구슬 생각하기
- 빨간 구슬이 구멍에 빠지고 안빠지는 동시에 파란 구슬이 빠지고 안빠지는 경우 (총 4가지)
✍ 휴도 코드
x
int RED(방향)//빨간 공 먼저 이동시켜줘야 하는 경우
{
int red_ox = 0;
int blue_ox = 0;//빠짐 : 1 / 안빠짐 : 0 표식
int rx = RED큐 x좌표
int ry = RED큐 y좌표
while (1)
{
//빨간 공 한칸씩 이동함.
if //구멍에 빠짐
{
red_ox = 1;//빨강 구멍 빠짐
//빨간 공 한칸 더 이동 (빨간공 끝까지 이동해서 좌표에 없애서 파란공 구멍에 빠지는지 봄)
}
if //벽이거나 파란구슬 만나면
{
break;
}
}//빨강 먼저 옮김
int new_rx = rx - dx[direction];
int new_ry = ry - dy[direction];//빨간공 좌표가 바꼈으니 갱신
int bx = BLUE큐 x좌표
int by = BLUE큐 y좌표
while (1)
{
//파란 공 한칸씩 이동함.
if //구멍에 빠짐
{
blue_ox = 1;//파란 구멍 빠짐
//파란 공 이동
}
if //벽이거나 빨강구슬 만나면
{
break;
}
}
// 빨강 | 파랑 O:구멍에 빠짐 X:안빠짐
// O | O : 실패 -1
// O | X : 성공
// X | O : 실패 -1
// X | X : 계속 이동하세요 ~
if (blue_ox == 1) return -1;//파란 구슬 구멍에 빠짐
else if (red_ox == 0 && blue_ox == 0)//빨간 파란 둘 다 안빠짐 --> 다음 방향 dir큐에 넣어줌.
{
R.push(make_pair(rx - dx[direction], ry - dy[direction]));
B.push(make_pair(bx - dx[direction], by - dy[direction]));
return 0;//빨강 파랑 둘 다 이동됨.
}
else if (red_ox == 1 && blue_ox == 0) return cnt;//빨간 구슬만 구멍에 빠짐. 답 저장
}
구현
x
using namespace std;
int arr[12][12];
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
int cnt = 0;
queue<int>dir;
queue<pair<int, int>>R;
queue<pair<int, int>>B;
int bfs();
int red(int direction);
int blue(int direction);
int main()
{
static int n, m;
cin >> n >> m;
static int rrx;
static int rry;
static int rbx;
static int rby;
for (int i = 0; i < n; i++)
{
string str;
cin >> str;
for (int j = 0; j < m; j++)
{
string s = str.substr(j, 1);
if (s.compare("#") == 0) arr[i][j] = -1;
else if (s.compare("O") == 0) arr[i][j] = 1;//구멍
else if (s.compare(".") == 0) arr[i][j] = 0;
else if (s.compare("R") == 0)
{
R.push(make_pair(i, j));//RED 좌표
rrx = i;
rry = j;
arr[i][j] = 44;
}
else if (s.compare("B") == 0)
{
B.push(make_pair(i, j));//BLUE 좌표
rbx = i;
rby = j;
arr[i][j] = 66;
}
}
}
priority_queue<int, vector<int>, greater<int> > answer;
int ans = 0;
for (int i = 0; i < 4; i++)
{
dir.push(i);
ans = bfs();
if (ans != -1)answer.push(ans);
while (!dir.empty())
dir.pop();
while (!R.empty())
R.pop();
while (!B.empty())
B.pop();
R.push(make_pair(rrx, rry));
B.push(make_pair(rbx, rby));
}
if (!answer.empty())
cout << answer.top();//정답
else
cout << -1 << endl;
}
int bfs()
{
for (cnt = 1; cnt < 11; cnt++)
{
int num = dir.size();
for (int a = 1; a <= num; a++)
{
int d = dir.front();
dir.pop();
if (d == 0)//상
{
if (R.front().first < B.front().first)//red 먼저 이동
{
int a = red(d);
if (a == 0)//red blue 둘다 이동
{
dir.push(2);
dir.push(3);
}//좌우 넣어줌
else if (a > 0)
return cnt;//bfs 함수 종료
}
else
{
int b = blue(d);
if (b == 0)//red blue 둘다 이동
{
dir.push(2);
dir.push(3);
}//좌우 넣어줌
else if (b > 0)
return cnt;
}
}//상
if (d == 1)//하
{
if (R.front().first > B.front().first)//red 먼저 이동
{
int a = red(d);
if (a == 0)//red blue 둘다 이동
{
dir.push(2);
dir.push(3);
}//좌우 넣어줌
else if (a > 0)
return cnt;
}
else
{
int b = blue(d);
if (b == 0)//red blue 둘다 이동
{
dir.push(2);
dir.push(3);
}//좌우 넣어줌
else if (b > 0)
return cnt;
}
}//하
if (d == 2)//좌
{
if (R.front().second < B.front().second)//red 먼저 이동
{
int a = red(d);
if (a == 0)//red blue 둘다 이동
{
dir.push(0);
dir.push(1);
}//좌우 넣어줌
else if (a > 0)
return cnt;
}
else
{
int b = blue(d);
if (b == 0)//red blue 둘다 이동
{
dir.push(0);
dir.push(1);
}//좌우 넣어줌
else if (b > 0)
return cnt;
}
}//좌
if (d == 3)//우
{
if (R.front().second > B.front().second)//red 먼저 이동
{
int a = red(d);
if (a == 0)//red blue 둘다 이동
{
dir.push(0);
dir.push(1);
}//좌우 넣어줌
else if (a > 0)
return cnt;
}
else
{
int b = blue(d);
if (b == 0)//red blue 둘다 이동
{
dir.push(0);
dir.push(1);
}//좌우 넣어줌
else if (b > 0)
return cnt;
}
}//우
if (a%2==0 || num == 1)
{
R.pop();
B.pop();
}//한 방향당 2개의 방향을 추가시키기 때문에 2개씩 끊어서 pop해줌(dir크기 1이면 무조건 pop)
}//dir.size만큼 도는 것
}
return -1;
}
int red(int direction)//주의 :
{
int red_ox = 0;
int blue_ox = 0;//빠짐 : 1 / 안빠짐 : 0 표식
int rx = R.front().first;
int ry = R.front().second;
while (1)
{
rx += dx[direction];
ry += dy[direction];
if (arr[rx][ry] == 1)
{
red_ox = 1;//빨강 구멍 빠짐
rx += dx[direction];
ry += dy[direction];// 더 가 !
}
if (rx == B.front().first && ry == B.front().second || arr[rx][ry] == -1)//벽이거나 파란구슬 만나면
{
break;
}
}//빨강 먼저 옮김
int new_rx = rx - dx[direction];
int new_ry = ry - dy[direction];
int bx = B.front().first;
int by = B.front().second;
while (1)
{
bx += dx[direction];
by += dy[direction];
if (arr[bx][by] == 1)
{
blue_ox = 1;//파랑 구멍 빠짐 실패 -1
bx += dx[direction];
by += dy[direction];
}
if (bx == new_rx && by == new_ry|| arr[bx][by] == -1)//벽이거나 빨간구슬 만나면
{
break;
}
}
if (blue_ox == 1) return -1;
else if (red_ox == 0 && blue_ox == 0)
{
R.push(make_pair(rx - dx[direction], ry - dy[direction]));
B.push(make_pair(bx - dx[direction], by - dy[direction]));
return 0;//빨강 파랑 둘 다 이동됨.
}
else if (red_ox == 1 && blue_ox == 0) return cnt;
}
int blue(int direction)
{
int red_ox = 0;
int blue_ox = 0;//빠짐 : 1 / 안빠짐 : 0 표식
int bx = B.front().first;
int by = B.front().second;
while (1)
{
bx += dx[direction];
by += dy[direction];
if (arr[bx][by] == 1)
{
blue_ox = 1;//파랑 구멍 빠짐 실패 -1
bx += dx[direction];
by += dy[direction];
}
if (bx == R.front().first && by == R.front().second || arr[bx][by] == -1)//벽이거나 빨간구슬 만나면
{
break;
}
}
int new_bx = bx - dx[direction];
int new_by = by - dy[direction];
int rx = R.front().first;
int ry = R.front().second;
while (1)
{
rx += dx[direction];
ry += dy[direction];
//cout << rx << ry << endl;
if (arr[rx][ry] == 1)
{
red_ox = 1;//빨강 구멍 빠짐
rx += dx[direction];
ry += dy[direction];
}
if (rx == new_bx && ry == new_by || arr[rx][ry] == -1)//벽이거나 파란구슬 만나면
{
break;
}
}//빨강 먼저 옮김
if (blue_ox == 1) return -1;
else if (red_ox == 0 && blue_ox == 0)
{
B.push(make_pair(bx - dx[direction], by - dy[direction]));
R.push(make_pair(rx - dx[direction], ry - dy[direction]));
return 0;//빨강 파랑 둘 다 이동됨.
}
else if (red_ox == 1 && blue_ox == 0) return cnt;
}
'BOJ' 카테고리의 다른 글
[백준 14809] 경사로 (1) | 2020.04.20 |
---|---|
[백준 14502] 연구소 (0) | 2020.04.15 |
[백준 14500] 테트로미노 (0) | 2020.03.29 |
[백준 14501] 퇴사 (0) | 2020.03.24 |
[백준 12100] 2048(Easy) (0) | 2020.02.29 |
- Total
- Today
- Yesterday
- IT#it#삼성#백준#경사로#코로나#화이팅
- iT#it#백준#시험감독#코로나#이겨내요#대한민국#화이팅
- 백준#알고리즘#코로나#IT#구슬탈출2#13460#공부#개인공부#독학#노력
- it#일상#코로나#그만#백준#알고리즘#안드로이드#개발자
- IT#백준#연구소#DFS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |