백준 14890번 - 경사로

황제연·2025년 1월 15일
0

알고리즘

목록 보기
154/169
post-thumbnail

문제 탐색하기

입력 자료 정리

  1. n은 지도의 세로/가로 길이다.
  2. k은 경사로의 길이다
  3. 이어서 들어오는 nxn의 값은 각 지점의 높이다

해결방법 추론

  1. 입력 최대 크기도 작고, 조건도 까다롭기 때문에 복잡한 구현문제라고 생각했다
  2. 문제는 이해했는데, 처음에 잘못된 선택을 해서 시간을 많이 소요한 문제다
  3. 선택지는 두가지였다. 첫번째는 경사로를 미리 설치하고 탐색하는 것이고
    두번째는 탐색하면서 경사로를 설치하는 조건이면 확인 후 설치하는 것이다
  4. 처음에는 첫번째 선택지로 구현하였다
  5. 먼저 세로줄과 가로줄을 따로 탐색하고, 두 지점간에 차이가 1인 경우 경사로를 설치하기로 결정했다
    그리고 경사로를 설치하면 다른 방향에서 해당 지점에 다시 경사로를 설치할 때, 설치하지 못하도록 방문배열을 활용했다
  6. 하지만 해당 방법의 경우 다음 문제가 존재한다. 설치 경사로가 좌 -> 우인지 우 <- 좌인지도 구분해야한다
    이 문제를 겪고 나니 해당 방법으로 해결하기에는 코드가 너무 난잡해져서 다른 방법을 고민했다
  7. 두번째 선택한 방법은 탐색하면서 필요할 때만 경사로를 설치하는 것이다
  8. 해당 경우는 앞선 경우와 다르게 4가지 메소드를 2가지 메소드로만 구현해도 되었기에 조금 편하게 구현할 수 있었다
  9. 이번에는 탐색하면서 만약 차이가 1이 되는 지점이 생긴다면 현재지점이 큰지 다음 지점이 큰지 구분해서
    경사로를 설치하도록 설계했다
  10. 해당 경우에는 반드시 한 방향으로만 설치하도록 설계하였고, 똑같이 방문배열을 통해 같은 방향에서 중복으로 설치하지 못하도록 설계했다
  11. 이렇게 설계한 결과 드디어 모든 예제를 통과할 수 있었다

시간복잡도 계산

  1. 시간복잡도는 n^2만큼 탐색하면서 k길이의 경사로를 놓는 연산을 합해서
    O(n^2 x k)의 시간복잡도가 발생한다
  2. 따라서 구현문제로 풀어도 시간제한안에 문제를 해결할 수 있다

코드 설계하기

입력값 상태 관리

  1. 모든 크기 입력값은 int형 변수로 관리하며, 각 지점의 높이는 int형 2차원 배열에 보관했다
    크기는 n x n이다
  2. 정답을 출력하기 위해 ans를 0으로 초기화하였다

구현 코드 설계

세로줄 가로줄 구분

  1. 세로줄과 가로줄을 구분하기 위해 둘을 다른 메소드로 구분하였고, 각각 n만큼 탐색했다
  2. 조건에 맞는 경우 ans를 증가시킨다
  3. 각 메소드에서는 경사로의 방문상태를 체크하는 n크기의 1차원 방문배열을 선언한다
  4. 아래 공통 부분은 고정/변동 인덱스의 위치만 서로 다를 뿐이지 로직은 똑같다

(공통) 차이 계산 및 검증

  1. 처음에는 차이를 절댓값으로 계산했으나 현재와 다음 지점 중 더 큰 지점을 확인하기 위해,
    절댓값을 사용하지 않고 차이를 변수에 담았다
  2. 만약 차이가 1보다 크거나 -1보다 작은 경우 조건을 만족하지 못하므로 false를 리턴한다

(공통) 다음 지점이 더 큰 경우

  1. 다음 지점이 큰경우 차이는 -1이다.
  2. 해당 경우, k만큼 탐색하면서 경사로를 설치한다
  3. i-j가 0보다 작거나 해당 인덱스의 경사로를 이미 설치한 경우 false를 리턴한다
  4. 이어서 처음 지점 i와 i-j 지점의 높이가 같지 않으면 false를 리턴한다
  5. 모든 조건을 만족하는 경우 경사로 배열의 i-j인덱스 값을 true로 설정한다

(공통) 현재 지점이 더 큰 경우

  1. 해당 경우는 위와 같이 진행하는데, i+j인 경우로 변경해서 진행한다
  2. 또한 0보다 작은 경우가 아닌 n이상인 경우 false를 리턴하도록 한다
  1. 모든 조건을 만족하면 true를 리턴한다

출력값 설계

  1. 완성한 ans를 출력하면 정답이 된다!

정답 코드

import java.io.*;
import java.util.*;


public class Main {


    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());
        int[][] arr = new int[n][n];
        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < n; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        int ans = 0;

        for (int i = 0; i < n; i++) {
            if(checkHor(n,arr,i,k)){
                ans++;
            }
        }

        for (int i = 0; i < n; i++) {
            if(checkVer(n,arr,i,k)){
                ans++;
            }
        }

        bw.write(ans+"");

        br.close();
        bw.close();
    }

    private static boolean checkVer(int n, int[][] arr, int vertical, int k){
        boolean[] cline = new boolean[n];

        for (int i = 0; i < n - 1; i++) {
            int diff = arr[vertical][i] - arr[vertical][i+1];
            if(diff > 1 || diff < -1){
                return false;
            }else if(diff == -1){
                for (int j = 0; j < k; j++) {
                    if(i - j < 0 || cline[i-j]){
                        return false;
                    }
                    if(arr[vertical][i] != arr[vertical][i-j]){
                        return false;
                    }
                    cline[i-j] = true;
                }
            }else if(diff == 1){
                for (int j = 1; j <= k; j++) {
                    if(i+j >= n || cline[i+j]){
                        return false;
                    }
                    if(arr[vertical][i] - 1 != arr[vertical][i+j]){
                        return false;
                    }
                    cline[i+j] = true;
                }
            }
        }

        return true;
    }

    private static boolean checkHor(int n, int[][] arr, int horizontal, int k) {
        boolean[] cline = new boolean[n];

        for (int i = 0; i < n - 1; i++) {
            int diff = arr[i][horizontal] - arr[i+1][horizontal];
            if(diff > 1 || diff < -1){
                return false;
            }else if(diff == -1){
                for (int j = 0; j < k; j++) {
                    if(i- j < 0 || cline[i-j]){
                        return false;
                    }
                    if(arr[i][horizontal] != arr[i-j][horizontal]){
                        return false;
                    }
                    cline[i-j] = true;
                }
            }else if(diff == 1){
                for (int j = 1; j <= k; j++) {
                    if(i+j >= n || cline[i+j]){
                        return false;
                    }
                    if(arr[i][horizontal] - 1 != arr[i+j][horizontal]){
                        return false;
                    }
                    cline[i+j] = true;
                }
            }
        }

        return true;
    }

}

문제 링크

14890번 - 경사로

profile
Software Developer

0개의 댓글