알고리즘/BOJ 문제풀이

[백준] 19237 어른 상어

4Legs 2021. 3. 30. 18:32

문제 링크 : www.acmicpc.net/problem/19237

 

19237번: 어른 상어

첫 줄에는 N, M, k가 주어진다. (2 ≤ N ≤ 20, 2 ≤ M ≤ N2, 1 ≤ k ≤ 1,000) 그 다음 줄부터 N개의 줄에 걸쳐 격자의 모습이 주어진다. 0은 빈칸이고, 0이 아닌 수 x는 x번 상어가 들어있는 칸을 의미

www.acmicpc.net

문제 유형

구현, 시뮬레이션

 

이전 문제인 [백준] 17822 원판 돌리기 와 같이, 상어를 클래스 형태로 구현한다.

동일 칸에서는 작은 상어가 반드시 남게 되므로, 상어의 이동은 번호가 높은 순으로 진행한다. 이렇게 하면 따로 예외 처리를 하지 않고도 덮어쓰기 개념으로 겹치는 상어에 대한 처리를 할 수 있게 된다.

이 풀이에서는 상어의 냄새가 어떤 상어의 것인지 나타내는 board와, 냄새의 남은 시간을 표현한 scent 배열을 통해 상어의 다음 이동 칸을 구했다.

상어의 현재 방향에 따른 우선순위를 통해, 현재 냄새가 없는(즉, scent 값이 0) 칸을 찾고, 만약 이러한 칸이 없다면 자신의 냄새가 존재하는 칸을 동일 우선순위로 찾는다. (자신의 냄새가 존재하는 칸은 k > 1일 때 반드시 존재한다.)

상어의 이동과 냄새 값을 갱신할 때, 죽은 상어에 대한 예외 처리나 순서 관련한 디버깅을 꼼꼼하게 해 주어야 한다.

 

[코드]

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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
typedef pair<intint> p;
typedef pair<p, int> pp;
 
p dir[4= { {-10}, {10}, {0-1}, {01} };
int board[21][21], scent[21][21];
int n, m, k;
bool dead[401];
 
class shark {
private:
    int num;
    int curdir;
    int dir_priority[4][4];
    int row, col;
 
public:
    pp find_nextpos() {
        //현재 위치에서 다음으로 이동할 칸을 찾는다
        p secondary = { 00 };
        int res_dir = -1;
        bool flag = false;
 
        //빈칸을 먼저 찾음
        for (int i = 0; i < 4; i++) {
            int nextdir = dir_priority[curdir][i];
            int newR = row + dir[nextdir].first, newC = col + dir[nextdir].second;
 
            if (newR < 1 || newR > n || newC < 1 || newC > n) continue;
 
            //냄새가 없는 칸을 발견
            //이전에 이동했던 상어가 이동한 후여도 그 결과를 반환
            //번호가 높은 상어는 이미 이동을 마쳤다는 가정이 있으므로, 덮어씌울 수 있다.
            if (scent[newR][newC] == 0 ) {
                if (board[newR][newC]) {
                    //이미 상어가 있는 경우
                    dead[board[newR][newC]] = true;
                }
                return { { newR, newC }, nextdir };
            }
 
            //자신의 냄새인 칸을 발견 시 보류
            if (board[newR][newC] == num) {
                if (!flag) {
                    flag = true
                    secondary = { newR, newC }; 
                    res_dir = nextdir; 
                }
            }
        }
 
        //냄새가 없는 칸을 발견하지 못했을 경우, secondary 반환
        return { secondary, res_dir };
    }
 
    void move() {
        //다음 이동할 칸을 찾음
        pp res = find_nextpos();
        p nextpos = res.first;
 
        //위치 및 방향정보 갱신
        row = nextpos.first; col = nextpos.second;
        curdir = res.second;
        board[row][col] = num;
    }
 
    void left_scent() {
        //현재 칸에 냄새를 남김
        scent[row][col] = k;
        board[row][col] = num;
    }
 
    void set_num(int number) { num = number; }
 
    void set_pos(int r, int c) { row = r; col = c; }
 
    void set_curdir(int d) { curdir = d; }
 
    void set_dir_priority(int d, int* priority) {
        for (int i = 0; i < 4; i++) dir_priority[d][i] = *(priority + i);
    }
};
 
shark sharks[401];
 
int get_alive() {
    int ret = 0;
    for (int i = 1; i <= m; i++)
        if (!dead[i]) ret++;
 
    return ret;
}
 
void update_scent() {
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (scent[i][j]) {
                scent[i][j] -= 1;
                if (scent[i][j] == 0) board[i][j] = 0;
            }
        }
 
    for (int i = 1; i <= m; i++)
        if (!dead[i]) sharks[i].left_scent();
}
 
void sharks_move() {
    for (int i = m; i >= 1; i--)
        if(!dead[i]) sharks[i].move();
}
 
void init() {
    int dval;
    cin >> n >> m >> k;
 
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            cin >> board[i][j];
            if (board[i][j]) {
                scent[i][j] = k;
                sharks[board[i][j]].set_num(board[i][j]);
                sharks[board[i][j]].set_pos(i, j);
            }
        }
 
    for (int i = 1; i <= m; i++) {
        cin >> dval;
        sharks[i].set_curdir(dval - 1);
    }
 
    for (int i = 1; i <= m; i++) {
        for (int j = 0; j < 4; j++) {
            int priority[4];
 
            for (int d = 0; d < 4; d++) {
                cin >> dval;
                priority[d] = dval - 1;
            }
 
            sharks[i].set_dir_priority(j, priority);
        }
    }
}
 
void print() {
    printf("[board]\n");
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            printf("%d ", board[i][j]);
        printf("\n");
    }
 
    printf("[scent]\n");
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            printf("%d ", scent[i][j]);
        printf("\n");
    }
}
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(NULL);
 
    int answer = 0;
    init();
    //print();
    while (get_alive() > 1) {
        if (answer > 1000break;
        //printf("------------------\nTime : %d\n", answer + 1);
        sharks_move();
        update_scent();
        //print();
        answer++;
    }
 
    if (answer > 1000) answer = -1;
    printf("%d\n", answer);
 
    return 0;
}
cs

 

 

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

[백준] 17822 원판 돌리기  (0) 2021.03.30
[백준] 5670 휴대폰 자판  (0) 2021.03.02
[백준] 8452 그래프와 쿼리  (0) 2021.03.02
[백준] 11003 최솟값 찾기  (0) 2021.02.28
[백준] 1945 직사각형  (0) 2021.02.27