알고리즘 스터디 1주차 문제3 (뱀)

문제#

algorithm-1-3

풀이 및 주저리..

역시나 저번에 이어서 시뮬레이션 문제였다. 정답비율이 너무 낮아서 시작전에 이걸 내가 과연 풀 수 있을까..? 라고 생각하면서 시작했었는데 신기하게 처음 시뮬레이션을 풀었던 로봇 청소기 문제보다 시간이 적게 걸리고 풀었던 것 같다. 시뮬레이션 문제에 조금씩 감이 잡히는 것 같기도하고.. 문제를 잘 이해하고 따라가는 실력이 늘어난 것 같기도 하다. 방향을 회전하거나 좌표를 구해서 움직이는 방법에 좀 친숙해진 느낌이라서 좋았다.

풀면서 중점이 됐던 부분은 어떻게 뱀이 지나간 위치(몸)를 기억하는 것과 매초 시간이 지날때 규칙이 어떻게 진행 되는지 였던 것 같다. 지나간 위치는 java 에서 제공해주는 컬렉션 프레임워크 중 deque를 잘 활용해서 풀었던 것 같다. 시간 지날때마다 몸의 변화 규칙은 하나하나 천천히 생각해보면서 어떤 규칙이 먼저인지 따져보며 풀어보니 한 두번의 수정으로만으로 해결할 수 있었다.

규칙: 뱀의 몸길이를 늘려 머리를 다음칸에 위치시킨다.(가장 먼저 다음 위치가 벽인지 아니면 자신의 몸중에 한부분이라도 좌표값이 같은지 확인해본다.) => 벽이나 몸의 일부분이면 종료. 아니라면 사과의 유/무 확인 후 꼬리부분(deque.pollFirst()) 를 할지 말지를 결정. 시간이 지날때 마다 방향변경을 담고있는 맵이 key(시간) 값을 갖고 있는지 확인하며 진행.

코드

package backjoon.algorthim.simulation;

import java.awt.Point;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/*
 * 게임은 NxN 정사각 보드위에서 진행되고
 * 보드의 상하좌우 끝에 벽이 있다. 
 * 게임이 시작할때 뱀은 맨위 맨좌측에 위치하고 뱀의 길이는 1 이다. 
 * 뱀은 처음에 오른쪽을 향한다.
 * 
 * 뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따른다.
 * 
 * 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
 * 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
 * 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.
사과의 위치와 뱀의 이동경로가 주어질 때 이 게임이 몇 초에 끝나는지 계산하라.
 * 
 * 첫째 줄에 보드의 크기 N이 주어진다. (2 ≤ N ≤ 100) 
 * 다음 줄에 사과의 개수 K가 주어진다. (0 ≤ K ≤ 100)
 * 
 * 다음 K개의 줄에는 사과의 위치가 주어지는데, 첫 번째 정수는 행, 
 * 두 번째 정수는 열 위치를 의미한다. 사과의 위치는 모두 다르며, 맨 위 맨 좌측 (1행 1열) 에는 사과가 없다.
 */
public class Problem3190 {
	static int N, K, L;
	static int[][] map;
	static int time = 0;
	static final int[][] DIR = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };
	static boolean isGame = true;
	static Map<Integer, Character> dir_map = new HashMap<Integer, Character>();

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		N = Integer.parseInt(br.readLine());
		map = new int[N + 2][N + 2];
		K = Integer.parseInt(br.readLine());

		for (int i = 0; i < N + 2; i++) {
			map[0][i] = 1;
			map[N + 1][i] = 1;
			map[i][0] = 1;
			map[i][N + 1] = 1;
		} // 맵 제일 끝 부분 벽으로 만들기.

		for (int i = 0; i < K; i++) {
			String[] a_xy = br.readLine().split(" ");
			map[Integer.parseInt(a_xy[0])][Integer.parseInt(a_xy[1])] = 3;
		}

		

		L = Integer.parseInt(br.readLine());
		for (int i = 0; i < L; i++) {
			String[] arr_dir = br.readLine().split(" ");
			dir_map.put(Integer.parseInt(arr_dir[0]), arr_dir[1].toCharArray()[0]);
		}
		Snake snake = new Snake();
		while (isGame) {
			time++;
			snake.go();
			if (dir_map.containsKey(time)) {
				snake.changeDir(dir_map.get(time));
			}

		}
		System.out.println(time);
		
//		for (int i = 0; i < map.length; i++) {
//			for (int j = 0; j < map[i].length; j++) {
//				System.out.print(map[i][j]);
//			}
//			System.out.println();
//		} 맵 출력

	}

	static class Snake {
		Deque<Point> body = new LinkedList<Point>();
		int dir = 0;

		public Snake() {
			body.addLast(new Point(1, 1));
		}

		public void go() {
			int y = body.peekLast().y + DIR[dir][1];
			int x = body.peekLast().x + DIR[dir][0];


			for (Point pt : body) {
				if (pt.x == x && pt.y == y) {
					isGame = false;
				}
			}
			if (map[y][x] == 1) {
				isGame = false;
				return;
			} else if (map[y][x] == 0) {
				body.pollFirst();
			} else if (map[y][x] == 3) {
				map[y][x] = 0;
			}

			body.addLast(new Point(x, y));
		}

		public void changeDir(char c) {
			if (c == 'D') {
				dir = (dir + 1) % 4;
			} else if (c == 'L') {
				dir = dir - 1 >= 0 ? dir - 1 : 3;
			}
		}

	}
}
algorithm-1-3-c

풀고나서 기록을 하루 넘긴다음 남기다보니 제출한 시간이 1일전이다.

기억에 남길 것!

  • 언제나 시작점과 끝점은 중요하다.
  • 문제를 잘 보고 클래스로 어떻게 만들면 좋을지 구상을 완벽하게 하고 접근하면 문제가 쉬워진다.
  • 남들이 어렵다고 생각해도 나한테는 쉬운문제일 수도 쉽다고 생각해도 나한테는 어려운 문제일 수도 있다.
  • java라는 언어가 가지고 있는 collection framework 를 잘쓴다면 정말 많은 도움이 된다.
© 2020 JunhoBaik, Built with Gatsby