[백준 1063번] 킹 with Java

guswls·2024년 5월 11일
0

알고리즘

목록 보기
30/39
post-custom-banner

문제


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



코드


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

class Main {
	static final int MAX_SIZE = 8;
	static final int KING = 0;
	static final int STONE = 1;

	static Map<String, Pos> direction = new HashMap<>();

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		Pos[] poses = new Pos[2];
		for (int i = 0; i < 2; i++) {
			char[] input = st.nextToken().toCharArray();
			poses[i] = new Pos(input[0] - 'A' + 1, input[1] - '0');
		}

		initializeDirection();

		int N = Integer.parseInt(st.nextToken());

		for (int i = 0; i < N; i++) {
			// 방향 구하기
			String dir = br.readLine();
			int dx = direction.get(dir).x;
			int dy = direction.get(dir).y;

			// 다음 좌표
			int nx = poses[KING].x + dx;
			int ny = poses[KING].y + dy;

			// 범위 벗어나면 건너뜀.
			if (!(1 <= nx && nx <= MAX_SIZE) || !(1 <= ny && ny <= MAX_SIZE)) {
				continue;
			}

			// 움직일 위치에 돌이 있다면 돌을 밀어냄.
			if (nx == poses[STONE].x && ny == poses[STONE].y) {
				int snx = poses[STONE].x + dx;
				int sny = poses[STONE].y + dy;

				// 돌이 범위를 벗어나면 건너뜀.
				if (!(1 <= snx && snx <= MAX_SIZE) || !(1 <= sny && sny <= MAX_SIZE)) {
					continue;
				}

				poses[STONE].x = snx;
				poses[STONE].y = sny;
			}

			// 다음 좌표로 돌 갱신하기
			poses[KING].x = nx;
			poses[KING].y = ny;
		}

		System.out.println(poses[KING]);
		System.out.println(poses[STONE]);

	}

	static void initializeDirection() {
		direction.put("R", new Pos(1, 0));
		direction.put("L", new Pos(-1, 0));
		direction.put("B", new Pos(0, -1));
		direction.put("T", new Pos(0, 1));
		direction.put("RT", new Pos(1, 1));
		direction.put("LT", new Pos(-1, 1));
		direction.put("RB", new Pos(1, -1));
		direction.put("LB", new Pos(-1, -1));
	}

	static class Pos {
		int x;
		int y;

		Pos(int x, int y) {
			this.x = x;
			this.y = y;
		}

		@Override
		public String toString() {
//			return String.format("%d %d", x, y);
			return String.format("%c%d", x + 'A' - 1, y);
		}
	}
}


문제 이해


  • 체스판 위에 왕과 돌이 있다.
  • 가로축은 A ~ H, 세로축은 1~8까지 존재한다.
  • 이때 입력으로 들어오는 8가지의 방향에 대해서 왕을 움직인다.
  • 만약 움직였을 때 범위를 벗어난다면, 해당 이동을 건너뛴다.
  • 만약 왕이 이동했을 때 돌의 위치와 겹친다면, 돌을 왕이 이동한 같은 방향으로 밀어낸다.
  • 마찬가지로 밀려난 돌이 범위를 벗어난다면 해당 이동을 건너뛴다.
  • 위 동작을 반복한 후에 최종적인 왕과 돌의 최종 좌표를 구한다.


풀이 방법


  • 좌표 상에서 방향을 정해서 이동하는 문제 유형을 몇번 풀어봤다면, 이 문제 역시 쉽게 풀 수 있다.
  • 나의 경우는 아래와 같은 순서로 구현했다.
    1. x, y축을 묶어서 관리할 수 있도록 Pos 객체를 생성하였다.
    2. 왕의 좌표와 돌의 좌표를 크기 2의 배열에 저장한다.
    3. Map에 Character, Pos를 맵핑하여 저장한다. Pos는 이동 방향을 나타낸다.
    4. 입력에 따라서 이동 방향을 Map에서 꺼내서 구한 다음, 여러 조건을 검사하고 필요에 따라 왕과 돌을 움직인다.
    5. 출력형식에 맞게 좌표를 출력한다.


핵심 포인트


  • 2차원 배열을 만들 필요가 없다. 방향에 따라 이동한 위치를 기록할 필요가 없기 때문에 왕과 돌의 마지막 좌표만 관리해주면 된다.
  • 좌표를 꼭 0-base로 맞출 필요가 없다. 이 문제의 경우는 1-base로 하여 문제에 나온 그대로 조건을 검사하는 것이 훨씬 직관적이고 이해하기 쉽다.
  • 코드가 유사한 부분이 많이 반복되는데, 복붙할 때마다 값을 잘 바꿔주어야 한다.


보완할 점 / 느낀 점


  • 문제 자체는 쉬운 문제였고, 구현 역시 빠르게 끝냈으나 실수를 많이 했던 문제였다.
  • 우선 처음에는 돌을 움직이는 것인줄 알았는데 돌이 아니라 왕을 움직이는 문제였다. 예제 입력2에서 계속 이동이 걸렸었다.
  • 또한 int ny = poses[KING].y + dy;이런 형태의 코드를 nx 갱신 코드에서 복붙해서 넣었는데, 값을 안바꾸고 넣었다. 역시 이것 때문에 많은 시간을 디버깅에 사용했다.
  • 이런 실수가 발생한 이유가 물론 나의 집중력 부족 탓도 있었겠지만, 가독성의 문제도 있었던 것 같다.
  • 지금 보니 왕과 돌의 경우, Pos배열이 아니라 각각의 Pos객체로 관리하는 것이 훨씬 가독성이 좋아보인다.
  • 물론 같이 사용되는 값을 지역성을 고려해 묶어놓는 것도 나쁘지 않은 판단일 수 있으나, 이번 문제는 해당 사항이 아니었던 것 같다.
  • 이 문제를 끝으로 solved.ac #implementation 실버문제 첫 페이지를 모두 풀었다.
  • 싸피 코테에 대비하여 쉬운 구현문제를 쭉 밀어봤는데 어려웠던 문제를 한번씩 다시 풀어보고, 남은 시간동안 백준 dfs문제와 swea D3문제 풀이를 병행해야겠다.


참고자료


profile
안녕하세요
post-custom-banner

0개의 댓글