카테고리 없음

[JAVA/자바] 백준 BAEKJOON 1063번 킹

remazitensi 2024. 8. 22. 03:06

문제링크

https://www.acmicpc.net/problem/1063

문제 풀이

첫 번째 풀이법 (BufferedReader 및 BufferedWriter 사용)

  1. 입력 처리:
    • BufferedReader를 사용하여 킹과 돌의 초기 위치, 그리고 이동 명령어 개수를 읽어옵니다.
    • 킹과 돌의 위치는 문자와 숫자로 주어지므로, 이를 행과 열의 좌표로 변환합니다. 변환 과정에서 indexToThing 메서드를 사용하여 'H1'을 (0, 7)로 변환합니다.
  2. 명령어 처리:
    • 이동 명령어들을 배열에 저장하고, 각 명령어를 처리합니다.
    • 각 명령어에 대해 방향을 결정하고, 킹과 돌이 이동해야 하는지 확인합니다.
    • isThereStone 메서드를 통해 킹의 이동 방향에 돌이 있는지 확인하고, 돌도 함께 이동해야 하는지 판단합니다.
  3. 이동 유효성 검사:
    • 킹과 돌이 이동할 새로운 위치가 체스판 범위 내에 있는지 확인합니다. 체스판 범위를 벗어날 경우 해당 이동은 무시합니다.
    • move 메서드를 사용하여 킹과 돌을 이동시키고, 유효한 이동만 반영합니다.
  4. 결과 출력:
    • 최종적으로 킹과 돌의 위치를 체스판의 문자와 숫자 형식으로 변환하여 출력합니다. 변환 과정에서는 thingToIndex 메서드를 사용하여 좌표를 다시 문자와 숫자 형식으로 변환합니다.

두 번째 풀이법 (HashMap 사용)

  1. 입력 처리:
    • Scanner를 사용하여 킹과 돌의 초기 위치, 그리고 이동 명령어 개수를 읽어옵니다.
    • 킹과 돌의 위치를 알파벳과 숫자 형식에서 체스판의 좌표로 변환합니다. 예를 들어 'H1'을 (7, 0)으로 변환합니다.
  2. 방향 변환:
    • 방향에 따른 좌표 변화량을 HashMap에 저장하여, 각 명령어가 어떻게 좌표를 변화시키는지 정의합니다. 예를 들어 "R"은 (0, 1)로 좌표를 오른쪽으로 이동시킵니다.
  3. 이동 처리:
    • 각 명령어를 읽고, 방향에 따른 좌표 변화를 적용하여 킹과 돌의 새로운 위치를 계산합니다.
    • 킹의 새로운 위치가 체스판 내에 있는지 확인하고, 만약 킹이 이동한 위치에 돌이 있으면 돌도 이동시킵니다. 돌의 새로운 위치도 체스판 내에 있는지 확인합니다.
  4. 결과 출력:
    • 최종적으로 킹과 돌의 위치를 체스판의 문자와 숫자 형식으로 변환하여 출력합니다. 이 과정에서 좌표를 다시 문자와 숫자 형식으로 변환합니다.

 

코드

  • 첫 번째 방법은 BufferedReader와 BufferedWriter를 사용하여 빠르게 입력과 출력을 처리하며, 직접적으로 방향 변화량을 배열로 관리하고, 킹과 돌의 위치를 객체로 처리
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 입력 받기
        String kingPos = scanner.next();  // 킹의 위치
        String stonePos = scanner.next();  // 돌의 위치
        int n = scanner.nextInt();  // 움직이는 횟수

        // 방향에 따른 좌표 변화량을 맵에 저장
        Map<String, int[]> directions = new HashMap<>();
        directions.put("R", new int[]{0, 1});
        directions.put("L", new int[]{0, -1});
        directions.put("B", new int[]{-1, 0});
        directions.put("T", new int[]{1, 0});
        directions.put("RT", new int[]{1, 1});
        directions.put("LT", new int[]{1, -1});
        directions.put("RB", new int[]{-1, 1});
        directions.put("LB", new int[]{-1, -1});

        // 킹과 돌의 초기 위치를 좌표로 변환
        int kingX = kingPos.charAt(1) - '1';
        int kingY = kingPos.charAt(0) - 'A';
        int stoneX = stonePos.charAt(1) - '1';
        int stoneY = stonePos.charAt(0) - 'A';

        // 움직임 처리
        for (int i = 0; i < n; i++) {
            String move = scanner.next();
            int[] dir = directions.get(move);

            int newKingX = kingX + dir[0];
            int newKingY = kingY + dir[1];

            // 킹이 이동한 위치가 체스판 안에 있을 경우
            if (isInsideBoard(newKingX, newKingY)) {
                // 킹의 새로운 위치가 돌의 위치와 같을 경우 돌을 이동시킴
                if (newKingX == stoneX && newKingY == stoneY) {
                    int newStoneX = stoneX + dir[0];
                    int newStoneY = stoneY + dir[1];

                    // 돌의 새로운 위치가 체스판 안에 있어야 함
                    if (isInsideBoard(newStoneX, newStoneY)) {
                        stoneX = newStoneX;
                        stoneY = newStoneY;
                        kingX = newKingX;
                        kingY = newKingY;
                    }
                } else {
                    kingX = newKingX;
                    kingY = newKingY;
                }
            }
        }

        // 최종 위치를 알파벳+숫자 형식으로 변환하여 출력
        System.out.println((char) (kingY + 'A') + "" + (kingX + 1));
        System.out.println((char) (stoneY + 'A') + "" + (stoneX + 1));
    }

    // 체스판 안에 있는지 확인하는 메서드
    private static boolean isInsideBoard(int x, int y) {
        return x >= 0 && x < 8 && y >= 0 && y < 8;
    }
}
  • 두 번째 방법은 Scanner와 HashMap을 사용하여 입력과 방향 변화를 간단하게 처리하고, 킹과 돌의 위치를 직접 좌표로 계산하여 이동합니다. 이 방법은 코드가 더 간결하고, HashMap을 통해 방향 변화를 매핑
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {

    // 킹과 돌의 위치를 표현하는 내부 클래스
    static class Thing {
        int r, c;

        // 생성자: 행과 열 좌표를 받아서 초기화
        public Thing(int r, int c) {
            this.r = r;
            this.c = c;
        }
    }

    static Thing king, stone;  // 킹과 돌의 위치를 저장하는 객체
    static String[] cmds;      // 이동 명령어들을 저장하는 배열
    static int N;              // 명령어 개수
    static int[] dr = {0, -1, -1, -1, 0, 1, 1, 1};  // 행 변화량: L, LT, T, RT, R, RB, B, LB 순
    static int[] dc = {-1, -1, 0, 1, 1, 1, 0, -1};  // 열 변화량: L, LT, T, RT, R, RB, B, LB 순

    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(), " ");
        king = indexToThing(st.nextToken());  // 킹의 위치를 좌표로 변환
        stone = indexToThing(st.nextToken());  // 돌의 위치를 좌표로 변환
        N = Integer.parseInt(st.nextToken());  // 이동 명령어 개수

        cmds = new String[N];
        for (int i = 0; i < N; i++) {
            String cmd = br.readLine();
            int direction = getDirection(cmd);  // 명령어를 방향 인덱스로 변환
            boolean withStone = isThereStone(direction);  // 이동할 방향에 돌이 있는지 확인
            move(direction, withStone);  // 킹과 돌을 이동
        }

        // 최종 위치 출력
        String k = thingToIndex(king);  // 킹의 위치를 알파벳+숫자 형식으로 변환
        String s = thingToIndex(stone);  // 돌의 위치를 알파벳+숫자 형식으로 변환
        bw.write(k + "\n" + s);
        bw.flush();
        bw.close();
        br.close();
    }

    // 체스판 위치를 행과 열 좌표로 변환하는 메서드 (예: H1 -> r, c 좌표)
    static Thing indexToThing(String index) {
        int c = index.charAt(0) - 'A';  // 열 계산
        int r = 8 - (index.charAt(1) - '0');  // 행 계산
        return new Thing(r, c);
    }

    // 행과 열 좌표를 체스판 위치로 변환하는 메서드 (예: r, c 좌표 -> H1)
    static String thingToIndex(Thing thing) {
        char c = (char) (thing.c + 'A');  // 열을 알파벳으로 변환
        char r = (char) (8 - thing.r + '0');  // 행을 숫자로 변환
        return "" + c + r;
    }

    // 명령어를 이동 방향 인덱스로 변환하는 메서드
    static int getDirection(String cmd) {
        switch (cmd) {
            case "L": return 0;
            case "LT": return 1;
            case "T": return 2;
            case "RT": return 3;
            case "R": return 4;
            case "RB": return 5;
            case "B": return 6;
            default: return 7;  // "LB"
        }
    }

    // 킹이 이동할 방향에 돌이 있는지 확인하는 메서드
    static boolean isThereStone(int direction) {
        int nr = king.r + dr[direction];
        int nc = king.c + dc[direction];
        return stone.r == nr && stone.c == nc;  // 이동할 위치에 돌이 있으면 true 반환
    }

    // 킹과 돌을 이동시키는 메서드
    static void move(int direction, boolean withStone) {
        if (withStone) {  // 돌도 함께 움직여야 할 때
            int nr = stone.r + dr[direction];
            int nc = stone.c + dc[direction];
            // 돌이 체스판을 벗어나지 않으면 이동
            if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
                stone.r = nr;
                stone.c = nc;
            } else {
                return;  // 돌이 벗어나면 이동 무시
            }
        }
        // 킹이 체스판을 벗어나지 않으면 이동
        int nr = king.r + dr[direction];
        int nc = king.c + dc[direction];
        if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) {
            king.r = nr;
            king.c = nc;
        }
    }
}