import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;
// 물고기의 좌표와 크기를 담는다
class Fish{
int x;
int y;
int size;
Fish(int x, int y, int size){
this.x = x;
this.y = y;
this.size = size;
}
}
// BFS를 위해 필요한 클래스
class Pair{
int x;
int y;
Pair(int x, int y){
this.x = x;
this.y = y;
}
}
public class Main {
static int[] dx = {1, -1, 0, 0};
static int[] dy = {0, 0, 1, -1};
static int n;
static Fish baby;
static List<Fish> list;
static int[][] check;
static int[][] map;
static int dist;
// 남은 모든 물고기가 다 크거나 같다면 참을 반환
static boolean allBigger() {
int size = baby.size;
for(int i = 0 ; i < list.size() ; i++) {
if(size > list.get(i).size) {
return false;
}
}
return true;
}
// 물고기까지 가는 거리를 계산
static int reachable(int idx) {
Queue<Pair> q = new LinkedList<>();
q.add(new Pair(baby.x, baby.y));
check[baby.x][baby.y] = 0; // 0에서 출발
int gx = list.get(idx).x; // 목표지점의 행
int gy = list.get(idx).y; // 목표지점의 열
while(!q.isEmpty()) {
Pair p = q.remove();
int x = p.x;
int y = p.y;
if( x == gx && y == gy) { // 도달했다면
return dist = check[x][y]; // 반환
}
for(int k = 0 ; k < 4 ; k++) { // 네 방향으로 갈 수 있다
int nx = x + dx[k];
int ny = y + dy[k];
// 맵에 존재하는지, 방문한적이 없는지
if(nx >= 0 && nx < n && ny >= 0 && ny < n && check[nx][ny] == -1) {
if(baby.size >= map[nx][ny]) { // 지나갈 수 있는지
check[nx][ny] = check[x][y] + 1;
q.add(new Pair(nx, ny));
}
}
}
}
// 도착하지 못했다면 최대거리 반환(20x20짜리 맵이 최대라서 대충 500보단 늘 거리가 작다)
return 500;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
list = new ArrayList<Fish>();
baby = new Fish(-1, -1, 2);
map = new int[n][n];
for(int i = 0 ; i < n ; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for(int j = 0 ; j < n ; j++) {
int size = Integer.parseInt(st.nextToken());
if(size == 0) {
continue;
}else if(size == 9) {
baby.x = i; baby.y = j;
}else {
list.add(new Fish(i, j, size));
map[i][j] = size;
}
}
}
int time = 0;
int eaten = 0; // 사이즈업 직후부터 먹은 물고기 수 저장
while(true) {
// 더이상 물고기가 없거나 아기상어보다 큰 물고기만 남았다면..
if(list.size() == 0 || allBigger()) {
break;
}
int x = baby.x;
int y = baby.y;
int size = baby.size;
int min = 500; // 먹이까지의 거리
int fx = -1; // 먹이의 행
int fy = -1; // 먹이의 열
int idx = -1; // 먹이의 인덱스
for(int i = 0 ; i < list.size() ; i++ ) {
if(list.get(i).size < size) { // 먹이는 아기상어보다 작아야 함
check = new int[n][n]; // check 배열 초기화
for(int row = 0 ; row < n ; row++) {
Arrays.fill(check[row], -1);
}
int dist = reachable(i); // 먹이까지의 거리 산출
if(dist < min) { // 최소 거리 갱신
min = dist;
fx = list.get(i).x;
fy = list.get(i).y;
idx = i;
}
}
}
// 최소거리 갱신에 실패했다 -> 먹을 물고기는 있지만 갈 수가 없다 -> 종료
if(min == 500) break;
time += min; // 걸린 시간 = 거리*1 이므로
baby.x = fx; // 아기상어의 위치를 옮겨준다
baby.y = fy;
eaten++; // 먹는다
if(eaten == size) { // 사이즈 업 조건
baby.size++;
eaten = 0;
}
// 먹이의 흔적을 지운다
list.remove(idx);
map[fx][fy] = 0;
}
System.out.println(time);
}
}
Comments