기술 블로그

13460번 구슬 탈출 2 본문

알고리즘 문제/BOJ

13460번 구슬 탈출 2

parkit 2018. 8. 21. 21:04
728x90
반응형

삼성 SW 역량 테스트 기출문제이다.


역시나 어렵다.


삼성같은 경우 DFS, BFS와 함께 Simulation, Brute Force를 결합한 문제를 자주 출제하는 것 같다.


예전에 어떤 분 코드 참고하였는데, 그 분 블로그를 까먹었다 ㅠ



https://www.acmicpc.net/problem/13460




이 문제 풀면서 생각해야할 것.


1. visit 배열을 활용할 때, 2차원 배열로만 생각하지 말자.

   (더군다나 문제에서 공은 같이 움직이기 때문에 같이 처리해줘야한다.)

2. 수학 관련 메서드를 생각해보자. (여기에서는 abs())

3. 81번 째 줄 코드가 있는 이유는 빨간 구슬, 파란 구슬 둘 다 빠지면 탈출 실패이기 때문이다.(주석도 참고).





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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <math.h>
#include <algorithm>
 
using namespace std;
 
int N = 0, M = 0// 세로 = y = N, 가로 = x = M → 헷갈릴까봐 적어두는 편이다.
 
bool visit[13][13][13][13= { false, }; // 공이 같이 움직인다. 방문 여부를 2차원 배열로만 생각하지 말자. 
 
char map[13][13]; // 전역 변수로 선언
 
int ry = 0, rx = 0, by = 0, bx = 0// 빨간 구슬, 파란 구슬 위치
 
int dy[4= { -1010 };
int dx[4= { 0-101 };
 
queue<pair<pair<intint>pair<intint> > > q; // ry, rx, by, bx 순
 
int BFS()
{
    q.push({ {ry, rx}, {by, bx} }); // queue에 push
 
    visit[ry][rx][by][bx] = true// 방문 표시
 
    int ret = 0// 답
 
    while (!q.empty())
    {
        int qSize = q.size();
 
        while (qSize--// 시간 단축
        {
            int Ry = q.front().first.first;
            int Rx = q.front().first.second;
 
            int By = q.front().second.first;
            int Bx = q.front().second.second;
 
            q.pop();
 
            if (map[Ry][Rx] == 'O' && map[Ry][Rx] != map[By][Bx]) // 문제 조건(빨간 구슬 위치 != 파란 구슬 위치)
            {
                return ret;
            }
 
            for (int i = 0; i < 4; i++)
            {
                int Red_y = Ry; int Red_x = Rx;
                int Blue_y = By; int Blue_x = Bx;
 
                while (map[Red_y + dy[i]][Red_x + dx[i]] != '#' && map[Red_y][Red_x] != 'O')
                {
                    // 다음 위치와 현재 위치를 비교하면서 while문을 실행한다.
 
                    // 구슬은 벽(#)을 통과할 수 없다.
 
                    Red_y += dy[i];
                    Red_x += dx[i];
                }
 
                while (map[Blue_y + dy[i]][Blue_x + dx[i]] != '#' && map[Blue_y][Blue_x] != 'O')
                {
                    // 다음 위치와 현재 위치를 비교하면서 while문을 실행한다.
 
                    // 구슬은 벽(#)을 통과할 수 없다.
 
                    Blue_y += dy[i];
                    Blue_x += dx[i];
                }
 
                if (Red_y == Blue_y && Red_x == Blue_x) 
                {
                    // 중력을 통해 움직였으나(위 while 2개), 그 후 빨간 구슬과 파란 구슬의 위치가 같다면,
 
                    if (map[Red_y][Red_x] == 'O'continue
                    // 하지만 도착한 곳이 탈출 구멍(O)이라면 무시한다.
 
                    /* 
                      이유는 밑에 if문을 통해 빨간 구슬 또는 파란 구슬의 위치가 달라지게 되는데
                        ret가 1 증가하게 되고,
                       위에서 둘 중 하나는 탈출 구멍(O)이고, 둘의 위치가 달라지므로 return 되어버린다.
                    */
 
                    if (abs(Red_y - Ry) + abs(Red_x - Rx) < abs(Blue_y - By) + abs(Blue_x - Bx))
                    {
                        /*움직인 거리가 파란 구슬이 더 많다면,
                        (= 파란 구슬보다 빨간 구슬이 더 앞 쪽에 있었다. 
                           그러나 위치가 똑같을 순 없으니 파란 구슬의 위치를 조정해야한다.)
                        */
 
                        Blue_y -= dy[i];
                        Blue_x -= dx[i];
                    }
                    else // 그게 아니라면
                    {
                        Red_y -= dy[i];
                        Red_x -= dx[i];
                    }
                }
     
                if (visit[Red_y][Red_x][Blue_y][Blue_x]) continue// 방문 했다면 무시
 
                visit[Red_y][Red_x][Blue_y][Blue_x] = true// 방문 표시
                 
                q.push({ {Red_y, Red_x}, {Blue_y, Blue_x} });
            }
        }
 
        if (ret >= 10return -1// 문제 조건
 
        ++ret;
    }
 
    return -1// queue가 비어있다는 것은 위에서 무슨 일이 발생했다는 뜻이다.(예 : 탈출 실패)
}
 
int main(void)
{
    scanf("%d %d"&N, &M);
 
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; j++)
        {
            cin >> map[i][j]; // 붙어있는 문자들을 입력 받을 때에는 cin이 편하다. scanf 사용 X
 
            if (map[i][j] == 'R')
            {
                ry = i;
                rx = j;
            }
            else if (map[i][j] == 'B')
            {
                by = i;
                bx = j;
            }
        }
    }
 
    cout << BFS() << '\n';
 
    return 0;
}
cs





728x90
반응형

'알고리즘 문제 > BOJ' 카테고리의 다른 글

11053번 가장 긴 증가하는 부분 수열  (0) 2018.08.22
7562번 나이트의 이동  (0) 2018.08.22
2206번 벽 부수고 이동하기  (0) 2018.08.21
10989번 수 정렬하기 3  (0) 2018.08.21
1260번 DFS와 BFS  (0) 2018.08.21