백준 20208 - 진우의 민트초코우유

Updated:

Java

20208 번 - 진우의 민트초코우유

문제

첫번째 줄에 민초마을의 크기인 N과 진우의 초기체력 M, 그리고 민트초코우유를 마실때 마다 증가하는 체력의 양 H가 공백을 두고 주어진다. N, M, H는 모두 10보다 작거나 같은 자연수이다.

두번째 줄부터 N+1번째 줄에 N칸에 걸쳐서 민초마을의 지도가 주어진다. 각 칸은 공백을 두고 주어지며 지도상에서 진우의 집은 1, 민트초코우유는 2로 주어지며 빈 땅은 0으로 주어진다.
진우의 집은 무조건 한 곳이 주어지며 마을에 배달되는 민트초코우유의 총합은 10개를 넘지 않는다

초기 체력은 M이다. 여기에서 체력은 진우가 이동할 수 있는 거리를 나타낸다. 진우는 지도상에서 상, 하, 좌, 우로 1칸씩 이동할 수 있으며 이동하면 체력이 1만큼 줄어든다.
진우가 마을을 돌아다니다가 민트초코우유를 마신다면 체력이 H 만큼 증가하며 진우의 체력이 초기체력 이상으로 올라갈 수 있다. 체력이 0이 되는 순간 진우는 이동할 수 없다.

민트초코를 찾으러 돌아다니다가 마을 한복판에서 체력이 0이 되어 집으로 못 돌아가는 상황은 만들어져서는 안된다. 진우가 얼마나 많은 민트초코우유를 마시고 집으로 돌아올 수 있는지 알아보자.

접근 방법

처음에 BFS를 사용하여, 각 점들을 한칸 씩 이동해보며 우유를 모으는 방법을 사용하였으나 이는 방문 처리를 할 수 없으므로 시간초과가 난다.

문제에서 요구하는 것은 결국 얼마만큼의 초코우유를 모을 수 있는가를 요구하므로,
처음 지점에서 각 우유가 있는 위치들을 탐색하여, 현재 체력으로 갈 수 있으면 계속하여 다음 우유를 찾는 DFS로 해결해야한다.

또한 매번 우유에 도달하였을 때, 집으로 갈 수있는 체력이면 현재까지 모은 우유의 개수를 갱신해 준다.

코드

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

public class Main {
	static int n, M, H, result, count;
	static int[][] map;
	static int homeY;
	static int homeX;
	static boolean[] visH;
	static ArrayList<int[]> milk;
	
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("res/mainInput.txt"));	//제출 할 때 주석해야함
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer stk = new StringTokenizer(br.readLine());
    	n = stoi(stk.nextToken());
    	M = stoi(stk.nextToken());
    	H = stoi(stk.nextToken());
    	
    	map = new int[n][n];
    	milk = new ArrayList<>();
    	for(int i = 0; i < n; i++) {
    		stk = new StringTokenizer(br.readLine());
    		for(int j = 0; j < n; j++) {
    			map[i][j] = stoi(stk.nextToken());
    			if(map[i][j] == 1) {
    				homeY = i;
    				homeX = j;
    			}
    			else if(map[i][j] == 2) {
    				count++;
    				milk.add(new int[] {i,j});
    			}
    		}
    	}
    	visH = new boolean[count];
    	DFS(homeY, homeX, M, 0);
    	
    	System.out.println(result);
    	br.close();
	}
	
	// 우유 모으기 시작
	static void DFS(int y, int x, int h, int cnt) {
		int len;
		len = Math.abs(y - homeY) + Math.abs(x - homeX);
		if(len <= h) {		// 현재 우유 위치에서 집에 도달 할 수 있는 거리이면
			result = Math.max(result, cnt);
		}
		
		for(int i = 0; i < count; i++) {
			len = Math.abs(y - milk.get(i)[0]) + Math.abs(x - milk.get(i)[1]);
			// 현재 위치와 각 우유까지의 거리보다 체력이 크다면, 다음 우유를 탐색한다.  
			if(!visH[i] && len <= h) {
				visH[i] = true;
				DFS(milk.get(i)[0], milk.get(i)[1], h - len + H, cnt + 1);
				visH[i] = false;
			}
		}
	}
	
	static int stoi(String str) {
    	return Integer.parseInt(str);
    }
}

총평

후기

BFS인 것 같지만 DFS였던 나를 속인 문제.

개선할 점

없습니다.