-
[백준] 13460 구슬 탈출 2Problem Solving/Baekjoon Online Judge 2020. 3. 6. 19:23
[문제이해]
1. 맵에는 벽(#), 빨간구슬(R), 파란구슬(B), 구멍(O)이 각각 1개씩 존재한다.
2. 4가지 기울이기(왼쪽, 오른쪽, 위쪽, 아래쪽)를 통해 구슬을 굴릴 수 있다.
- 빨간구슬이 구멍에 빠지면 성공
- 파란구슬이 구멍에 빠지면 실패
- 빨간구슬과 파란구슬 모두 구멍에 빠져도 실패
- 기울이기를 10번 초과하면 실패
3. 보드의 상태가 주어졌을 때 최소 몇 번만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지를 계산해야한다.
[설계]
1. 빨간구슬과 파란구슬에 대해 상,하,좌,우 4방향 BFS를 적용한다.
2. 예를들어 맵을 오른쪽으로 기울였으면, 빨간구슬과 파란구슬 둘 다 오른쪽 방향 BFS를 적용한다.
3. 큐에다가 빨간구슬 x, y 좌표와 파란구슬 x, y 좌표 그리고 기울인 횟수 d를 넣어준다.
3. 기울이고 나서 구슬의 위치는 4차원 배열로 방문처리해둔다. bool visited[rx][ry][bx][by];
4. 구슬은 벽(#)을 만날때까지 굴러가야한다. 구슬에 대해 BFS를 적용할 때 이 부분을 처리해야한다.
5. 구슬이 서로 붙어 있는 경우를 고려해야한다. 더 멀리 이동한 구슬을 움직인 방향을 기준으로 한 칸 뒤로 배치시킨다.
6. 실패하면, -1을 출력 해야한다.[회고]
1. BFS를 사용하는 이유?
-> 최소한의 기울임으로 빨간 구슬을 구멍에 빠뜨려야한다.
-> BFS는 가중치가 없는 그래프에서 최단경로를 찾을 때 사용되므로 위 문제에 적용될 수 있다.2. 빨간 구슬과 파란구슬이 붙어있는 경우를 고려해야함
-> 처음에 생각지 못해서 어려웠다.
3. 4차원 배열을 통해 방문 처리
-> 처음에 빨간구슬 2차원 방문 배열, 파란구슬 2차원 방문 배열 이렇게 나눠서함
-> 빨간 구슬과 파란 구슬이 동시에 움직이기 때문에 4차원 배열을 사용해서 한 번에 방문 처리해야함.
[코드]
#include<iostream> #include<queue> using namespace std; typedef struct { int rx, ry, bx, by, d; }pos; char map[10][10]; int n, m; int res = 11; bool visited[10][10][10][10]; int dx[] = { -1,1,0,0 }, dy[] = { 0,0,-1,1 }; queue<pos> q; void move(int &x, int &y, int &Cnt, int dx, int dy) { while (map[x+dx][y+dy] != '#' && map[x][y] != 'O'){ x += dx; y += dy; Cnt++; } } void bfs() { while (!q.empty()) { int rx = q.front().rx, ry = q.front().ry; int bx = q.front().bx, by = q.front().by; int d = q.front().d; q.pop(); if (d >= 10) continue;//기울인 횟수가 10이상이라면, 스킵한다. for (int i = 0; i < 4; i++) { int nrx = rx, nry = ry; //빨강 구슬의 새로운 좌표 int nbx = bx, nby = by; //파란 구슬의 새로운 좌표 int rCnt = 0, bCnt = 0; //빨강, 파랑 구슬이 굴러간 횟수를 카운트 하는 변수 move(nrx, nry, rCnt, dx[i], dy[i]); //빨간구슬 이동 move(nbx, nby, bCnt, dx[i], dy[i]); //파란구슬 이동 if (map[nbx][nby] == 'O') //파란 구슬이 구멍에 빠지면, 실패 continue; if (map[nrx][nry] == 'O') {//빨간 구슬만 구멍에 빠진 경우라면, 성공 res = min(res, d+1);//성공 했을 때, 최솟값 기록 continue; } if (nrx == nbx && nry==nby) {//구슬이 겹치는 경우 = 구슬이 붙어있는 경우 if (bCnt > rCnt) { //파란구슬이 더 멀리 갔다면, 한 칸 뒤로 nbx -= dx[i]; nby -= dy[i]; } else { //빨간구슬이 더 멀리 갔다면, 한 칸 뒤로 nrx -= dx[i]; nry -= dy[i]; } } if (visited[nrx][nry][nbx][nby]) continue; //이미 방문했다면(이미 알아본 경우의 수라면), 스킵 visited[nrx][nry][nbx][nby] = true; //방문처리 q.push({ nrx,nry,nbx,nby,d+1}); //다시 큐에 넣는다. } } } int main() { cin >> n >> m; int rx, ry, bx, by; //빨간구슬과 파란구슬의 초기위치 값을 저장하는 변수 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> map[i][j]; if (map[i][j] == 'R') { rx = i, ry = j; } else if (map[i][j] == 'B') { bx = i, by = j; } } } visited[rx][ry][bx][by]=true; q.push({ rx,ry,bx,by,0 }); //두 구슬의 초기위치, 기울인횟수(0)을 큐에 넣어준다. bfs(); if(res == 11) printf("-1"); else printf("%d", res); return 0; }
[출처]
'Problem Solving > Baekjoon Online Judge' 카테고리의 다른 글
[백준] 1038 감소하는 수 (0) 2020.04.15 [백준] 16234 인구이동 (0) 2020.03.26 [백준] 17141 연구소 2 (0) 2020.03.26 [백준] 16933 벽 부수고 이동하기 3 (0) 2020.03.24 [백준] 16197 두 동전 (0) 2020.03.08