백준_달이 차오른다, 가자._1194[Java]

2019. 4. 12. 18:55알고리즘문제/백준

문제

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

 

1194번: 달이 차오른다, 가자.

첫째 줄에 미로의 세로 크기 N과 가로 크기 M이 주어진다. (N,M <= 50) 둘째 줄부터 N개의 줄에 미로의 모양이 주어진다. 같은 타입의 열쇠가 여러 개 있을 수 있고, 문도 마찬가지이다. 그리고, 영식이가 열쇠를 숨겨놓는 다면 문에 대응하는 열쇠가 없을 수도 있다. 0은 한 개, 1은 적어도 한 개 있다. 그리고, 열쇠는 여러 번 사용할 수 있다.

www.acmicpc.net

 

앞서 풀었던 욕심쟁이 판다 문제와 흐름은 방법이 비슷한 부분이 있는데

이 문제의 핵심인 열쇠를 가지고 있는지 확인하는 과정에서 비트마스킹 방식이 들어가니 어려웠다. 

비트마스킹을 배우게 된 문제 ! 꺅 

 

 

흐름

BFS를 이용한 메소드를 호출한다.

완전 탐색을 강행하는데 한번 다녀온 위치는 이미 다녀왔음을 기록해둬 중복 방문 횟수를 줄인다. 

출구(1)를 찾았을 경우에는 메소드를 종료한다. 

 

3차원 배열인 visit 에 위치값 X, Y 그리고 해당 위치에 갔을 때 가지게 되는 키 정보를 담는다. 

키 정보는 아래와 같이 2진수로 담는다.

키를 획득했을 경우에는 1,  없을 경우에는 0으로 지정한다. 키 별 위치는 다음과 같다. 

    a    b    c    d    e    f                          

예를 들어 a키와 d키, 두 가지 키를 소유하고 있을 경우에는 100100(2)

 

따라서 f라는 키를 발견했을 때 1 << 'f' - 'a' 는 1 << 5 이므로 2의 6승 = 100000(2)다.

이 값을 OR연산하면 새로 획득한 키 정보를 추가할 수 있다. 

* 여기서 'a' , 'b', 'c', 'd', 'e', 'f', 는 각각 아스키코드로 97, 98, .. 102라는 것을 알아두자. 

 

문을 발견했을 때는 비슷한 방법으로 키를 가지고 있는지 확인하고 가지고 있다면 이동하고 

가지고 있다면 이동하지 않는다. 

 

코드

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	static int N, M;
	static char[][] miro;
	static boolean[][][] visit;
	static int result = 0;

	static class Dot{
		int x;
		int y;
		int key;
		
		Dot(int x, int y, int key){
			this.x = x;
			this.y = y;
			this.key = key;
		}
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		N = sc.nextInt();
		M = sc.nextInt();
		sc.nextLine();
		
		Dot start = null;
		miro = new char[N][M];
		String[] s = new String[N];
		visit = new boolean[N][M][1 << 6]; // 2의 6승을 만들어준다. 
		
		for(int i = 0; i < N; i++) {
			s = sc.nextLine().split("");
			for(int j = 0; j < M; j++) {
				miro[i][j] = s[j].charAt(0);
				if(miro[i][j] == '0') { // 민식이 위치
					start = new Dot(i, j, 0);
				}
			}
			
		}
		
		result = solution(start);
		System.out.println(result);
		sc.close();
	}

	// 하 상 우 좌 
	static int[] dx = {1, -1, 0, 0};
	static int[] dy = {0, 0, 1, -1};
	
	private static int solution(Dot start) {
		Queue<Dot> q = new LinkedList<Dot>();
		q.add(start);
		// peek : 가장 앞쪽에 위치한 값을 리턴해준다. 삭제X (가장 먼저 나갈 아이)
		visit[q.peek().x][q.peek().y][0] = true;

		int time = 0;
		while(!q.isEmpty()) {
			int size = q.size();
			for(int qsize = 0; qsize < size; qsize++) {
				// poll : 가장 앞쪽 위치한 값 리턴 및 q에서 삭제 
				Dot t = q.poll()	; 
				int curX = t.x;
				int curY = t.y;
				int curKey = t.key;
				
				if(miro[curX][curY] == '1') {
					return time;
				} // 기저사례 
				
				// 이동 : 상하좌우 가능 
				for(int i = 0; i < 4; i++) {
					int nextX = curX + dx[i];
					int nextY = curY + dy[i];
					int key = curKey;
					
					// 장외 
					if(nextX >= N || nextY >= M || nextX < 0 || nextY < 0) {
						continue;
					}
                    
					// 벽 발견 
					if(miro[nextX][nextY] == '#') {
						continue;
					}
                    
					// 키 발견 
					if('a' <= miro[nextX][nextY] && miro[nextX][nextY] <= 'f') {
						key |= (1 << miro[nextX][nextY] - 'a');
					}
					
					// 문 발견 
					if('A' <= miro[nextX][nextY] && miro[nextX][nextY] <= 'F') {
						if((key & (1 << (miro[nextX][nextY] - 'A'))) == 0) { // 키를 가지고 있지 않다면 
							continue;
						}
					}
					
					// 방문 이전에 했다면 패스 
					if(visit[nextX][nextY][key]) {
						continue;
					}
					
					visit[nextX][nextY][key] = true;
					q.add(new Dot(nextX,nextY, key)); 
					
				}
			}
			time++;
		}
		return -1;
		
	}

}

 

참고

- 비트 연산 참고하기

https://heedipro.tistory.com/245

불러오는 중입니다...

 

- 코드 및 흐름 참고

https://zoonvivor.tistory.com/158

 

[BOJ] 백준 1194 - 달이 차오른다, 가자. (자바)

BFS ...,,,,, 비트 마스크 .,,.,.. 이거 어떻게 풀지 몰라서 다른 사람들 코드를 보고 이해한 후 풀었다. 비트마스크가 이렇게 쓰일 수 있다는 것이 너무 신기했다. 풀이 1. BFS를 통해 탐색을 하면 된다. 2. 키의..

zoonvivor.tistory.com

 

- 알고리즘 문제 풀 때 C++로 푼 거 보는것도 재미땨  

https://jason9319.tistory.com/214

 

BOJ)1194 달이 차오른다, 가자.

문제: icpc.me/1194 가중치 없는 그래프에서의 최단거리를 구해야 하므로 BFS를 이용하면 된다, 이때 열쇠라는 조건이 추가로 붙는데 우리는 열쇠를 쥐고 있는 상태를 비트마스킹을 통하여 표현해주면 된다. qu의..

jason9319.tistory.com

 

'알고리즘문제 > 백준' 카테고리의 다른 글

백준_안전영역_2468[Java]  (0) 2019.04.19
백준_로봇_1726[Java]  (0) 2019.04.19
백준_욕심쟁이 판다_1937[Java]  (0) 2019.04.12
백준_시험감독[Java]_도움요청  (0) 2019.04.10
백준_구슬 탈출2[Java]_도움요청  (0) 2019.04.09