문제
https://www.acmicpc.net/problem/16236
풀이
문제의 핵심은 BFS를 사용하여 가장 가까운 먹이를 찾고 이를 반복하는 것이다.
이 부분에서 문제의 조건인 '먹을 수 있는 물고기가 1마리보다 많다면' 의 조건을 올바르게 구현하는데 많은 시간이 들었다.
첫 번째는 단순히 BFS의 사방 탐색 방향을 조건과 같이 위쪽 / 왼쪽 / 오른쪽 / 아래로 설정했으나, 이러한 방법이 문제가 있다는 사실을 파악하였다.
두 번째로 조건에 맞는 값들을 완전 탐색으로 전부 포집 후, 이를 소팅하려 했으나 의미없는 반복문이 너무 늘어나고 방향성을 수정하게 되었다.
bfs문을 돌리면서 상어가 먹을 수 있는 조건의 먹이들을 확인하고 이를 우선순위 큐에 집어넣어 정렬한 뒤 최소값을 찾는 방법을 생각해보았다.
이를 위해 bfs 메서드에서 돌아가는 q와, 우선순위 큐인 fish를 분리한다. 이후 조건(더 이상 탐색할 수 있는 먹이가 없음)에 맞을 때까지 while문을 돌려 값을 갱신한다.
소스 코드는 아래와 같다.
소스 코드
import java.util.*;
import java.io.*;
public class Main {
static int N, res = 0;
static int[][] map;
static boolean[][] visit;
static Shark baby = new Shark(-1, -1, 2, 0); //상어 설정
static Queue<int[]> q = new ArrayDeque<>(); // R / C / 시간
static PriorityQueue<int[]> fish = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[2] == o2[2]) {
if(o1[0] == o2[0]) {
return o1[1] - o2[1]; //가장 왼쪽에 있는 물고기
}
return o1[0] - o2[0]; //가장 위에 있는 물고기
}
return o1[2] - o2[2]; //가장 가까운 물고기
}
});
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
map = new int[N][N];
visit = new boolean[N][N];
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if(map[i][j] == 9) {
baby.r = i;
baby.c = j;
map[i][j] = 0; //초기화
}
}
}
while(true) {
bfs(); //먹이 탐색
if(fish.size() == 0) break; //기저조건 : 상어가 먹을 수 있는 먹이가 없음
int temp[] = fish.poll(); //먹을 물고기 저장한 값 (R, C, Time)
res += temp[2]; //시간 저장
baby.r = temp[0];
baby.c = temp[1]; //좌표 갱신
baby.eat();
map[baby.r][baby.c] = 0; //자리 초기화
q.clear(); //큐 초기화
fish.clear(); //
visit = new boolean[N][N]; //방문 초기화
}
System.out.println(res);
}
static void bfs() {
q.offer(new int[] {baby.r, baby.c, 0}); //상어가 가까운 먹이를 탐색
while(!q.isEmpty()) {
int[][] shift = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}}; //U L R D
int temp[] = q.poll(); //임시 값 빼오기
int r = temp[0];
int c = temp[1];
int time = temp[2];
//조건 : 작은 물고기를 발견했을 경우 fish Queue에 추가
if (map[r][c] != 0 && baby.size > map[r][c]) {
fish.offer(new int[] {r, c, time});
}
for (int i = 0; i < shift.length; i++) {
int nr = r + shift[i][0];
int nc = c + shift[i][1];
if(nr < 0 || nc < 0 || nr >= N || nc >= N || visit[nr][nc] || map[nr][nc] > baby.size) continue;
visit[nr][nc] = true; //방문 처리
q.offer(new int[] {nr, nc, time + 1});
}
}
}
static class Shark {
int r, c; //좌표
int size, eat; //크기, 현재 먹은 횟수
public Shark(int r, int c, int size, int eat) {
this.r = r;
this.c = c;
this.size = size;
this.eat = eat;
}
void eat() {
eat += 1;
if (size == eat) {
eat = 0;
size += 1;
}
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
2606 바이러스[S3] (1) | 2023.11.11 |
---|---|
1107 리모컨[G5] (0) | 2023.11.11 |
17144 - 미세먼지 안녕(G4) (0) | 2023.11.02 |
1780 - 종이의 개수(S2) (0) | 2023.11.02 |
2630 - 색종이 만들기(S2) (0) | 2023.11.02 |