N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다.
아기 상어와 물고기는 모두 크기를 가지고 있고, 이 크기는 자연수이다. 가장 처음에 아기 상어의 크기는 2이고, 아기 상어는 1초에 상하좌우로 인접한 한 칸씩 이동한다.
아기 상어는 자신의 크기보다 큰 물고기가 있는 칸은 지나갈 수 없고, 나머지 칸은 모두 지나갈 수 있다. 아기 상어는 자신의 크기보다 작은 물고기만 먹을 수 있다. 따라서, 크기가 같은 물고기는 먹을 수 없지만, 그 물고기가 있는 칸은 지나갈 수 있다.
아기 상어가 어디로 이동할지 결정하는 방법은 아래와 같다.
아기 상어의 이동은 1초 걸리고, 물고기를 먹는데 걸리는 시간은 없다고 가정한다. 즉, 아기 상어가 먹을 수 있는 물고기가 있는 칸으로 이동했다면, 이동과 동시에 물고기를 먹는다. 물고기를 먹으면, 그 칸은 빈 칸이 된다.
아기 상어는 자신의 크기와 같은 수의 물고기를 먹을 때 마다 크기가 1 증가한다. 예를 들어, 크기가 2인 아기 상어는 물고기를 2마리 먹으면 크기가 3이 된다.
공간의 상태가 주어졌을 때, 아기 상어가 몇 초 동안 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는지 구하는 프로그램을 작성하시오.
첫째 줄에 공간의 크기 N(2 ≤ N ≤ 20)이 주어진다.
둘째 줄부터 N개의 줄에 공간의 상태가 주어진다. 공간의 상태는 0, 1, 2, 3, 4, 5, 6, 9로 이루어져 있고, 아래와 같은 의미를 가진다.
아기 상어는 공간에 한 마리 있다.
첫째 줄에 아기 상어가 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는 시간을 출력한다.
3
0 0 0
0 0 0
0 9 0
0
import java.io.*;
import java.util.*;
class Fish implements Comparable<Fish> {
int r, c, dist;
Fish(int r, int c, int dist) {
this.r = r;
this.c = c;
this.dist = dist;
}
@Override
public int compareTo(Fish o) {
if (this.dist < o.dist) {
return -1;
} else if (this.dist == o.dist) {
if (this.r < o.r) {
return -1;
} else if (this.r == o.r) {
return Integer.compare(this.c, o.c);
} else {
return 1;
}
} else {
return 1;
}
}
}
public class Main {
static int[][] map = new int[21][21];
static boolean[][] visit = new boolean[21][21];
static int[] dr = {-1, 0, 0, 1}; // 상, 좌, 우, 하
static int[] dc = {0, -1, 1, 0};
static int shark_r, shark_c;
static int shark_size = 2;
static int N, fish_cnt = 0, ans = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
N = Integer.parseInt(br.readLine());
for (int i = 1; i <= N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 1; j <= N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if (map[i][j] == 9) { // 아기상어
shark_r = i;
shark_c = j;
}
}
}
babyShark(shark_r, shark_c);
bw.write(ans + "\n");
br.close();
bw.flush();
bw.close();
}
public static void babyShark(int r, int c) {
Queue<Fish> queue = new LinkedList<>();
queue.add(new Fish(r, c, 0));
PriorityQueue<Fish> pq = new PriorityQueue<>();
while (!pq.isEmpty() || !queue.isEmpty()) {
pq.clear();
while (!queue.isEmpty()) {
Fish cur = queue.poll();
visit[cur.r][cur.c] = true;
for (int i = 0; i < 4; i++) {
int next_r = cur.r + dr[i];
int next_c = cur.c + dc[i];
Fish next = new Fish(next_r, next_c, cur.dist + 1);
if (next_r > 0 && next_c > 0 && next_r <= N && next_c <= N && !visit[next_r][next_c]) {
if (map[next_r][next_c] > 0 && map[next_r][next_c] < shark_size) { // 물고기를 먹을 수 있는 경우
if (!pq.contains(next)) {
pq.add(next);
}
break;
} else if (pq.isEmpty() && map[next_r][next_c] <= shark_size) { // 물고기를 지나갈 수 있는 경우
if (!queue.contains(next)) {
queue.add(next);
visit[next_r][next_c] = true;
}
}
}
}
}
if (!pq.isEmpty()) {
Fish next_shark = pq.poll();
map[shark_r][shark_c] = 0; // 원래 상어가 있던 자리 빈칸으로 수정
shark_r = next_shark.r;
shark_c = next_shark.c;
fish_cnt++;
ans += next_shark.dist;
if (fish_cnt == shark_size) { // 상어의 크기와 이때까지 먹은 물고기 수가 같은 경우
shark_size++;
fish_cnt = 0;
}
next_shark.dist = 0;
queue.add(next_shark);
for (int row = 1; row <= N; row++) {
for (int col = 1; col <= N; col++) {
visit[row][col] = false;
}
}
} else {
break;
}
}
}
}
거의 6시간을 매달려 풀었다. 😂😂
어찌어찌 맞긴 했으나 잘 짠 코드는 아닌 것 같으니 다른 깔끔한 코드들을 참고하시길 바랍니다,, ㅎㅎ
알고리즘
1. 처음 아기 상어를 queue에 추가한다.
2. 주변 4방향을 살핀다.
- 물고기를 먹을 수 있는 경우 pq에 추가한다.
- 4방향 중에서 먹을 물고기가 없었고, 길을 지나갈 수 있는 경우 queue에 추가한다.
3. queue가 빌 때까지 2를 반복한다.
4. pq에 먹을 물고기가 존재하면
- 원래 아기 상어가 있던 자리 0으로 설정
- 아기 상어 먹은 물고기 위치로 변경
- 먹은 물고기 수 +1
- ans 갱신
- (현재 상어의 크기와 이때까지 먹은 물고기 수가 같다면)
아기 상어 크기+1
먹은 물고기 수 리셋
- visit 배열 초기화
5. pq에 먹을 물고기가 존재하지 않으면 종료