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로 이루어져 있고, 아래와 같은 의미를 가진다.
아기 상어는 공간에 한 마리 있다.
첫째 줄에 아기 상어가 엄마 상어에게 도움을 요청하지 않고 물고기를 잡아먹을 수 있는 시간을 출력한다.
1. 아기 상어 위치 찾기
입력 값을 이차원 배열 dp에 입력해준다.
그 중 9는 아기 상어의 위치를 의미하기 때문에 Queue에 아기 상어의 위치를 넣어주고 해당 위치를 방문할 수 있도록 0으로 초기화한다.
2. 아기 상어가 먹을 수 있는 물고기 최단 거리 구하기
bfs 함수에 현재 아기 상어 위치가 담겨있는 Queue와 아기 상어 사이즈를 전달하는 bfs 함수 내에는 먹을 수 있는 물고기를 담을 우선 순위 큐를 초기화 해놓는다.
Queue : 아기 상어가 먹을 수 있는 물고기까지의 최단 시간 구하기 위한 탐색 큐
PriorityQueue : 아기 상어가 먹을 수 있는 물고기를 우선순위를 정해서 담아놓은 큐
-> 거리가 가장 가까운 물고기 -> 거리가 같을 시 위에 있는 물고기 먹기 -> 이 또한 여러 마리라면, 왼쪽에 있는 물고기 먹기
현재 아기 상어 위치에서 아직 방문하지 않은 상하좌우 중 값이 0이거나, 물고기 크기가 아기 상어의 크기보다 작은 경우 Queue에 추가해 bfs를 진행한다.
3. 아기 상어가 먹을 수 있는 물고기로 이동
PriorityQueue에는 현재 크기의 상어가 먹을 수 있는 물고기가 우선순위대로 담겨있다.
이 과정을 반복한다.
만약 bfs를 마친 후 PriorityQueue에 담긴 값이 없다면 아기 상어가 먹을 수 있는 물고기가 없다는 뜻이기 때문에 탐색을 종료한다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
public class Gra16236 {
static int n;
static int[][] dp;
static PriorityQueue<Shark> pq = new PriorityQueue<>();
static int[] dy = {1, 0, -1, 0};
static int[] dx = {0, -1, 0, 1};
static class Shark implements Comparable<Shark> {
int y, x, dis;
public Shark(int y, int x, int dis) {
this.y = y;
this.x = x;
this.dis = dis;
}
@Override
public int compareTo(Shark o) {
if (this.dis != o.dis) return Integer.compare(this.dis, o.dis);
else {
if(this.y == o.y) return Integer.compare(this.x, o.x);
else return Integer.compare(this.y, o.y);
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
n = Integer.parseInt(br.readLine());
dp = new int[n][n];
Queue<Shark> q = new LinkedList<>();
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < n; j++) {
dp[i][j] = Integer.parseInt(st.nextToken());
if (dp[i][j]==9) {
dp[i][j] = 0;
q.offer(new Shark(i, j, 0));
}
}
}
bfs(q, 2);
int move = 0, cnt = 0, sharkSize = 2;
while (!pq.isEmpty()) {
Shark cur = pq.poll();
dp[cur.y][cur.x] = 0;
cnt++;
if (cnt == sharkSize) {
cnt = 0;
sharkSize++;
}
move += cur.dis;
q = new LinkedList<>();
q.offer(new Shark(cur.y, cur.x, 0));
bfs(q, sharkSize);
}
System.out.println(move);
}
static void bfs(Queue<Shark> q, int sharkSize) {
pq = new PriorityQueue<>();
boolean[][] visited = new boolean[n][n];
while (!q.isEmpty()) {
Shark cur = q.poll();
for (int i = 0; i < 4; i++) {
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= n || dp[ny][nx] > sharkSize || visited[ny][nx]) continue;
visited[ny][nx] = true;
q.offer(new Shark(ny, nx, cur.dis + 1));
if (dp[ny][nx] != 0 && dp[ny][nx] < sharkSize) {
pq.offer(new Shark(ny, nx, cur.dis + 1));
}
}
}
}
}