코테/코드트리

[코드트리/INTERMEDIATE LOW] K번 최댓값으로 이동하기 (JAVA)

imname1am 2024. 1. 28. 15:55
반응형

📖 문제

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

 

 

 

💡  풀이 방식

• BFS

1) 현재 위치에서 이동 가능한 칸 전부 찾기
2) 도달 가능한 칸 中 우선순위가 가장 높은 칸 위치 구하기
  - 도달 가능한 칸 있다면, 현재 칸 위치를 해당 위치로 옮기기
  - 도달 가능한 칸 없다면, 움직이기 종료

 

시작 위치에서 상하좌우에 본인보다 작은 값이 없다면, 이동할 수 없으므로 종료한다.

하지만 본인보다 작은 값이 존재한다면, 아래와 같이 진행한다.

 

1) bfs를 통해 배열을 탐색하며 방문 가능한(=격자 범위 내에 있고, 방문한 적 없고, 기준 점의 값보다 작은) 모든 점들을 방문하고, 이 점들을 리스트에 추가한다.

 

2) 점들을 저장한 리스트는 "숫자>행>열" 순으로 정렬해 우선순위가 가장 높은 칸의 위치를 구하고 이동한다. (=정렬 후 리스트의 0번째 값)

조건
1. 도달할 수 있는 칸들에 적힌 숫자들 중 최댓값으로 이동한다.
2. 1번 조건을 만족하는 숫자가 여러개인 경우, 행 번호가 가장 작은 곳으로 이동한다.
3. 2번 조건을 만족하고, 행 번호도 같은 숫자가 여러개인 경우, 열 번호가 가장 작은 곳으로 이동한다.
class Node implements Comparable<Node> {
    int r, c, val;

    public Node(int r, int c, int val) {
        this.r = r;
        this.c = c;
        this.val = val;
    }

    @Override
    public int compareTo(Node n) {
        if(this.val == n.val) { // [칸의 값이 같은 경우]
            if(this.r == n.r) { // 행 번호가 같다면, 열 기준 오름차순 정렬
                return this.c - n.c;
            }
            return this.r - n.r;    // 행 번호가 다르다면, 행 기준 오름차순 정렬
        }
        return n.val - this.val;    // [칸의 값이 다른 경우] 값 기준 내림차순 정렬
    }
}

 

 

 

🔺 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.util.*;
import java.io.*;
 
public class Main {
    static int[] dx = {-1,1,0,0};
    static int[] dy = {0,0,-1,1};
 
    static int N, K, r, c;
    static int[][] grid;
    static boolean[][] visited;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
 
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
 
        grid = new int[N+1][N+1];
 
        for(int i = 1 ; i <= N ; i++) {
            st = new StringTokenizer(br.readLine(), " ");
            for(int j = 0 ; j < N ; j++) {
                grid[i][j + 1= Integer.parseInt(st.nextToken());
            }
        }
 
        st = new StringTokenizer(br.readLine(), " ");
        r = Integer.parseInt(st.nextToken());
        c = Integer.parseInt(st.nextToken());
 
        while(K-->0){
            if(!smallerNumberExists())  // 상하좌우에 작은 값이 없어 이동할 수 없다면 pass
                break;
 
            // 상하좌우로 이동할 수 있다면, bfs 수행
            visited = new boolean[N + 1][N + 1];    // 방문배열 매번 초기화해야 함
            bfs();
        }
 
        System.out.println(r + " " + c);
    }
    
    // 상하좌우에 현재 칸의 값보다 작은 값이 존재하는지 확인하는 함수
    private static boolean smallerNumberExists() {
        for(int d = 0 ; d < 4 ; d++) {
            int nr = r + dx[d];
            int nc = c + dy[d];
 
            if(inRange(nr, nc) && grid[nr][nc] < grid[r][c])
                return true;
        }
 
        return false;
    }
 
    // 격자를 벗어나는지 확인하는 함수
    private static boolean inRange(int r, int c) {
        return (1 <= r && r <= N && 1 <= c && c <= N);
    }
 
    private static void bfs() {
        List<Node> list = new ArrayList<>();    // 해당 점에서 접근 가능한 모든 칸의 정보를 저장하는 리스트
 
        Queue<Node> q = new ArrayDeque<>();
        q.add(new Node(r, c, grid[r][c]));
 
        int targetNum = grid[r][c];
 
        while(!q.isEmpty()) {
            Node now = q.poll();
 
            for(int d = 0 ; d < 4 ; d++) {
                int nr = now.r + dx[d];
                int nc = now.c + dy[d];
 
                // 격자 범위 내에 있고, 방문한 적 없고, 해당 칸의 값보다 작다면, 큐와 리스트에 값 추가
                if(inRange(nr, nc) && !visited[nr][nc] && grid[nr][nc] < targetNum) {
                    visited[nr][nc] = true;
                    q.add(new Node(nr, nc, grid[nr][nc]));
                    list.add(new Node(nr, nc, grid[nr][nc]));
                }
            }
        }
 
        Collections.sort(list); // 조건에 맞게 정렬하고, 0번째 값으로 이동하도록 함
        r = list.get(0).r;
        c = list.get(0).c;
    }
}
 
class Node implements Comparable<Node> {
    int r, c, val;
 
    public Node(int r, int c, int val) {
        this.r = r;
        this.c = c;
        this.val = val;
    }
 
    @Override
    public int compareTo(Node n) {
        if(this.val == n.val) { // [칸의 값이 같은 경우]
            if(this.r == n.r) { // 행 번호가 같다면, 열 기준 오름차순 정렬
                return this.c - n.c;
            }
            return this.r - n.r;    // 행 번호가 다르다면, 행 기준 오름차순 정렬
        }
        return n.val - this.val;    // [칸의 값이 다른 경우] 값 기준 내림차순 정렬
    }
}
cs

 

 

➕ 다른 풀이 방식

비교할 때 튜플형 비교를 할 수 있다고 한다.

첫 번째 원소를 비교하고, 두 원소가 같다면 두 번째 원소를 비교하는 식으로 진행

if (숫자1, -행1, -열1) > (숫자2, -행2, -열2):
    숫자1의 우선순위가 더 높다.
else:
    숫자 2가 우선순위가 더 높다.

 


💦 어려웠던 점

- 소요시간 35분! 생각보다 짧게 걸려서 기쁜,,

 

 

 

1회독 2회독 3회독 4회독 5회독
V        

 

반응형