Skip to content

Commit ce87c23

Browse files
committed
[Gold I] Title: 어른 상어, Time: 0 ms, Memory: 2024 KB -BaekjoonHub
1 parent b0893e9 commit ce87c23

File tree

2 files changed

+285
-0
lines changed

2 files changed

+285
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# [Gold I] 어른 상어 - 19237
2+
3+
[문제 링크](https://www.acmicpc.net/problem/19237)
4+
5+
### 성능 요약
6+
7+
메모리: 2024 KB, 시간: 0 ms
8+
9+
### 분류
10+
11+
구현, 시뮬레이션
12+
13+
### 제출 일자
14+
15+
2026년 2월 19일 18:18:18
16+
17+
### 문제 설명
18+
19+
<p><a href="/problem/19236">청소년 상어</a>는 더욱 자라 어른 상어가 되었다. 상어가 사는 공간에 더 이상 물고기는 오지 않고 다른 상어들만이 남아있다. 상어에는 1 이상 M 이하의 자연수 번호가 붙어 있고, 모든 번호는 서로 다르다. 상어들은 영역을 사수하기 위해 다른 상어들을 쫓아내려고 하는데, 1의 번호를 가진 어른 상어는 가장 강력해서 나머지 모두를 쫓아낼 수 있다.</p>
20+
21+
<p>N×N 크기의 격자 중 M개의 칸에 상어가 한 마리씩 들어 있다. 맨 처음에는 모든 상어가 자신의 위치에 자신의 냄새를 뿌린다. 그 후 1초마다 모든 상어가 동시에 상하좌우로 인접한 칸 중 하나로 이동하고, 자신의 냄새를 그 칸에 뿌린다. 냄새는 상어가 k번 이동하고 나면 사라진다.</p>
22+
23+
<p>각 상어가 이동 방향을 결정할 때는, 먼저 인접한 칸 중 아무 냄새가 없는 칸의 방향으로 잡는다. 그런 칸이 없으면 자신의 냄새가 있는 칸의 방향으로 잡는다. 이때 가능한 칸이 여러 개일 수 있는데, 그 경우에는 특정한 우선순위를 따른다. 우선순위는 상어마다 다를 수 있고, 같은 상어라도 현재 상어가 보고 있는 방향에 따라 또 다를 수 있다. 상어가 맨 처음에 보고 있는 방향은 입력으로 주어지고, 그 후에는 방금 이동한 방향이 보고 있는 방향이 된다.</p>
24+
25+
<p>모든 상어가 이동한 후 한 칸에 여러 마리의 상어가 남아 있으면, 가장 작은 번호를 가진 상어를 제외하고 모두 격자 밖으로 쫓겨난다.</p>
26+
27+
<p style="text-align: center;"><img alt="" src="https://upload.acmicpc.net/149aa507-f474-43cb-9071-1959bb83d59a/-/preview/" style="width: 353px; height: 352px;"></p>
28+
29+
<p style="text-align: center;"><그림 1></p>
30+
31+
<table class="table table-border table table-bordered" style="width: 100%;">
32+
<thead>
33+
<tr>
34+
<th colspan="8" style="text-align: center;">우선 순위</th>
35+
</tr>
36+
</thead>
37+
<tbody>
38+
<tr>
39+
<th colspan="2" style="text-align: center;">상어 1</th>
40+
<th colspan="2" style="text-align: center;">상어 2</th>
41+
<th colspan="2" style="text-align: center;">상어 3</th>
42+
<th colspan="2" style="text-align: center;">상어 4</th>
43+
</tr>
44+
<tr>
45+
<th style="text-align: center;">↑</th>
46+
<td style="text-align: center;">↓ ← ↑ →</td>
47+
<th style="text-align: center;">↑</th>
48+
<td style="text-align: center;">↓ → ← ↑</td>
49+
<th style="text-align: center;">↑</th>
50+
<td style="text-align: center;">→ ← ↓ ↑</td>
51+
<th style="text-align: center;">↑</th>
52+
<td style="text-align: center;">← → ↑ ↓</td>
53+
</tr>
54+
<tr>
55+
<th style="text-align: center;">↓</th>
56+
<td style="text-align: center;">→ ↑ ↓ ←</td>
57+
<th style="text-align: center;">↓</th>
58+
<td style="text-align: center;">↓ ↑ ← →</td>
59+
<th style="text-align: center;">↓</th>
60+
<td style="text-align: center;">↑ → ← ↓</td>
61+
<th style="text-align: center;">↓</th>
62+
<td style="text-align: center;">← ↓ → ↑</td>
63+
</tr>
64+
<tr>
65+
<th style="text-align: center;">←</th>
66+
<td style="text-align: center;">← → ↓ ↑</td>
67+
<th style="text-align: center;">←</th>
68+
<td style="text-align: center;">← → ↑ ↓</td>
69+
<th style="text-align: center;">←</th>
70+
<td style="text-align: center;">↑ ← ↓ →</td>
71+
<th style="text-align: center;">←</th>
72+
<td style="text-align: center;">↑ → ↓ ←</td>
73+
</tr>
74+
<tr>
75+
<th style="text-align: center;">→</th>
76+
<td style="text-align: center;">→ ← ↑ ↓</td>
77+
<th style="text-align: center;">→</th>
78+
<td style="text-align: center;">→ ↑ ↓ ←</td>
79+
<th style="text-align: center;">→</th>
80+
<td style="text-align: center;">← ↓ ↑ →</td>
81+
<th style="text-align: center;">→</th>
82+
<td style="text-align: center;">↑ → ↓ ←</td>
83+
</tr>
84+
</tbody>
85+
</table>
86+
87+
<p style="text-align: center;"><표 1></p>
88+
89+
<p><그림 1>은 맨 처음에 모든 상어가 자신의 냄새를 뿌린 상태를 나타내며, <표 1>에는 각 상어 및 현재 방향에 따른 우선순위가 표시되어 있다. 이 예제에서는 k = 4이다. 왼쪽 하단에 적힌 정수는 냄새를 의미하고, 그 값은 사라지기까지 남은 시간이다. 좌측 상단에 적힌 정수는 상어의 번호 또는 냄새를 뿌린 상어의 번호를 의미한다.</p>
90+
91+
<p style="text-align: center;"><img alt="" src="https://upload.acmicpc.net/b2d80580-57ba-419b-9d16-bc7fbe49512b/-/preview/" style="width: 900px; height: 352px;"></p>
92+
93+
<p style="text-align: center;"><그림 2></p>
94+
95+
<p style="text-align: center;"><img alt="" src="https://upload.acmicpc.net/52324aeb-3f7d-49b0-8128-560eb3742aa3/-/preview/" style="width: 901px; height: 358px;"></p>
96+
97+
<p style="text-align: center;"><그림 3></p>
98+
99+
<p><그림 2>는 모든 상어가 한 칸 이동하고 자신의 냄새를 뿌린 상태이고, <그림 3>은 <그림 2>의 상태에서 한 칸 더 이동한 것이다. (2, 4)에는 상어 2과 4가 같이 도달했기 때문에, 상어 4는 격자 밖으로 쫓겨났다.</p>
100+
101+
<p style="text-align: center;"><img alt="" src="https://upload.acmicpc.net/86821cd6-b638-43a1-8abb-99c917d6d324/-/preview/" style="width: 901px; height: 355px;"></p>
102+
103+
<p style="text-align: center;"><그림 4></p>
104+
105+
<p style="text-align: center;"><img alt="" src="https://upload.acmicpc.net/76e735b6-44e1-437c-9b69-b7f55ea29d02/-/preview/" style="width: 902px; height: 357px;"></p>
106+
107+
<p style="text-align: center;"><그림 5></p>
108+
109+
<p><그림 4>은 격자에 남아있는 모든 상어가 한 칸 이동하고 자신의 냄새를 뿌린 상태, <그림 5>는 <그림 4>에서 한 칸 더 이동한 상태를 나타낸다. 상어 2는 인접한 칸 중에 아무 냄새도 없는 칸이 없으므로 자신의 냄새가 들어있는 (2, 4)으로 이동했다. 상어가 이동한 후에, 맨 처음에 각 상어가 뿌린 냄새는 사라졌다.</p>
110+
111+
<p>이 과정을 반복할 때, 1번 상어만 격자에 남게 되기까지 몇 초가 걸리는지를 구하는 프로그램을 작성하시오.</p>
112+
113+
### 입력
114+
115+
<p>첫 줄에는 N, M, k가 주어진다. (2 ≤ N ≤ 20, 2 ≤ M ≤ N<sup>2</sup>, 1 ≤ k ≤ 1,000)</p>
116+
117+
<p>그 다음 줄부터 N개의 줄에 걸쳐 격자의 모습이 주어진다. 0은 빈칸이고, 0이 아닌 수 x는 x번 상어가 들어있는 칸을 의미한다.</p>
118+
119+
<p>그 다음 줄에는 각 상어의 방향이 차례대로 주어진다. 1, 2, 3, 4는 각각 위, 아래, 왼쪽, 오른쪽을 의미한다.</p>
120+
121+
<p>그 다음 줄부터 각 상어의 방향 우선순위가 상어 당 4줄씩 차례대로 주어진다. 각 줄은 4개의 수로 이루어져 있다. 하나의 상어를 나타내는 네 줄 중 첫 번째 줄은 해당 상어가 위를 향할 때의 방향 우선순위, 두 번째 줄은 아래를 향할 때의 우선순위, 세 번째 줄은 왼쪽을 향할 때의 우선순위, 네 번째 줄은 오른쪽을 향할 때의 우선순위이다. 각 우선순위에는 1부터 4까지의 자연수가 한 번씩 나타난다. 가장 먼저 나오는 방향이 최우선이다. 예를 들어, 우선순위가 1 3 2 4라면, 방향의 순서는 위, 왼쪽, 아래, 오른쪽이다.</p>
122+
123+
124+
<p>맨 처음에는 각 상어마다 인접한 빈 칸이 존재한다. 따라서 처음부터 이동을 못 하는 경우는 없다.</p>
125+
126+
### 출력
127+
128+
<p>1번 상어만 격자에 남게 되기까지 걸리는 시간을 출력한다. 단, 1,000초가 넘어도 다른 상어가 격자에 남아 있으면 -1을 출력한다.</p>
129+
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#include <iostream>
2+
#include <vector>
3+
#include <array>
4+
5+
#define UP 0
6+
#define DOWN 1
7+
#define LEFT 2
8+
#define RIGHT 3
9+
#define NO_SH (-1)
10+
#define DEBUG 0
11+
12+
using namespace std;
13+
using pos = pair<int, int>; // r, c
14+
using shark = pair<pos, int>; // 위치(r, c), direction
15+
16+
int N, M, K;
17+
pos out_pos = {-1, -1};
18+
vector<vector<pair<int, int>>> s_map;
19+
vector<shark> sharks;
20+
vector<array<array<int, 4>, 4>> s_prior;
21+
22+
void input() {
23+
cin >> N >> M >> K;
24+
25+
s_map.assign(N, vector<pair<int, int>>(N, {NO_SH, 0})); // NxN, {idx, remain_time}
26+
sharks.assign(M, {{0, 0}, 0}); // M, {{r, c}, dir}
27+
s_prior.assign(M, array<array<int, 4>, 4>()); // M, 벡터 안에 4x4 배열 - 각 상어마다 각 방향마다 우선순위 방향
28+
29+
for (int r = 0; r < N; r++) { // map 만들기
30+
for (int c = 0; c < N; c++) {
31+
int shark_idx = 0;
32+
cin >> shark_idx; // 0 or 상어 idx
33+
shark_idx--;
34+
s_map[r][c].first = shark_idx;
35+
if (shark_idx != NO_SH) { // 0이 아닌, 상어가 있다면
36+
s_map[r][c].second = K;
37+
sharks[shark_idx] = {{r, c}, UP}; // 방향은 UP으로 일단 초기화
38+
}
39+
}
40+
}
41+
42+
for (auto &shark : sharks) { // 방향 정하기
43+
cin >> shark.second; // direction
44+
shark.second--;
45+
}
46+
47+
for (auto &p : s_prior) { // 방향 우선순위 정하기
48+
for (int r = 0; r < 4; r++) {
49+
for (int c = 0; c < 4; c++) {
50+
cin >> p[r][c];
51+
p[r][c]--;
52+
}
53+
}
54+
}
55+
}
56+
57+
pos next_pos(const pos &c_pos, int c_dir) {
58+
pos next = c_pos;
59+
switch (c_dir) {
60+
case UP:
61+
next.first -= 1;
62+
break;
63+
case DOWN:
64+
next.first += 1;
65+
break;
66+
case LEFT:
67+
next.second -= 1;
68+
break;
69+
case RIGHT:
70+
next.second += 1;
71+
break;
72+
default: ;
73+
}
74+
if (next.first >= 0 && next.first < N && next.second >= 0 && next.second < N) return next;
75+
return {-1, -1};
76+
}
77+
78+
int main() {
79+
input();
80+
81+
int answer = 1;
82+
auto reserved = vector<shark>(M, {{0, 0}, 0}); // M, {{r, c}, dir}
83+
while (answer <= 1000) {
84+
// 상어 움직임
85+
for (int idx = 0; idx < M; idx++) {
86+
auto [c_pos, c_dir] = sharks[idx];
87+
if (c_pos == out_pos) continue; // Out된 상어라면, 넘어가기
88+
89+
int is_moved = 0;
90+
int first_matched_dir = -1;
91+
for (auto &next_dir : s_prior[idx][c_dir]) {
92+
auto n_pos = next_pos(c_pos, next_dir);
93+
if (n_pos == out_pos) continue;
94+
95+
const int n_r = n_pos.first;
96+
const int n_c = n_pos.second;
97+
if (s_map[n_r][n_c].first == NO_SH) { // 다음 위치에 냄새 없음
98+
reserved[idx] = {n_pos, next_dir}; // reserved에 저장
99+
is_moved = 1;
100+
break;
101+
}
102+
else if (s_map[n_r][n_c].first == idx && first_matched_dir == -1) { // 다음 위치가 자신인데, 아직 방향이 정해지지 X
103+
first_matched_dir = next_dir;
104+
}
105+
}
106+
if (!is_moved && first_matched_dir != -1) {
107+
reserved[idx] = {next_pos(c_pos, first_matched_dir), first_matched_dir};
108+
}
109+
}
110+
111+
// 맵 전체 k 감소
112+
for (auto &row : s_map) {
113+
for (auto &element : row) {
114+
if (element.first != NO_SH) {
115+
element.second--; // 냄새 감소
116+
if (element.second == 0) element.first = NO_SH; // 냄새가 0이면, 해당 위치의 idx도 NO로 변경
117+
}
118+
}
119+
}
120+
121+
// 맵 업데이트 (상어 겹치는지)
122+
for (int idx = 0; idx < M; idx++) {
123+
if (sharks[idx].first == out_pos) continue;
124+
125+
auto [c_pos, c_dir] = reserved[idx];
126+
const int c_r = c_pos.first;
127+
const int c_c = c_pos.second;
128+
const auto c_shark = s_map[c_r][c_c].first; // 해당 위치에 있는 상어 여부
129+
if (c_shark == NO_SH || s_map[c_r][c_c].second < K) { // 상어 없거나 남은 시간이 K보다 작으면(없다는 뜻)
130+
s_map[c_r][c_c] = {idx, K}; // map 업데이트
131+
sharks[idx].first = c_pos;
132+
sharks[idx].second = c_dir;
133+
} else if (c_shark > idx) { // 잡아먹을 수 있음
134+
s_map[c_r][c_c] = {idx, K}; // map 업데이트
135+
sharks[idx].first = out_pos;
136+
sharks[idx].second = c_dir; // c_shark를 쫓아내니까 필요 없는 듯?
137+
} else { // 잡아먹힘
138+
sharks[idx].first = out_pos; // map 업데이트 X
139+
}
140+
}
141+
142+
// End: 상어 1만 남았는지
143+
int remain_cnt = 0;
144+
for (auto &shark : sharks) {
145+
if (shark.first != out_pos) {
146+
remain_cnt++;
147+
}
148+
}
149+
150+
if (remain_cnt == 1) break;
151+
answer++;
152+
}
153+
154+
cout << ((answer > 1000) ? -1 : answer) << '\n';
155+
return 0;
156+
}

0 commit comments

Comments
 (0)