[BOJ 2842] 집배원 한상덕 (Java)

nnm·2020년 2월 27일
0

BOJ 2842 집배원 한상덕

문제풀이

이 문제는 투포인터 + 그래프 탐색 문제다. 방문한 칸 중 가장 높은 곳과 가장 낮은 곳의 차이가 피로도라고 한다. 이 때 가장 높은 곳과 가장 낮은 곳을 정하고 탐색 가능 여부에 따라서 가장 높은 곳과 가장 낮은 곳을 조정해나가면 된다.

  • 투 포인터를 사용하기 위해서는 높이가 정렬되어있어야 한다.
  • 탐색이 가능할 때는 min 값의 인덱스를 늘려주어 피로도를 감소시켜준다.
  • 탐색이 불가능할 때는 max 값의 인덱스를 늘려주어 피로도를 증가시켜준다.

구현코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {

	static class Node {
		int r, c;
		
		Node(int r, int c){
			this.r = r;
			this.c = c;
		}
	}
	
	static char[][] map;
	static int[][] heightMap;
	static ArrayList<Integer> heightList;
	static int N, house;
	static Node start;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		
		N = stoi(br.readLine());
		
		house = 0;
		map = new char[N][N];
		heightMap = new int[N][N];
		heightList = new ArrayList<>();
		
		// 데이터 입력 
		for(int r = 0 ; r < N ; ++r) {
			char[] line = br.readLine().toCharArray();
			for(int c = 0 ; c < N ; ++c) {
				map[r][c] = line[c];
				if(map[r][c] == 'K') house++;
				if(map[r][c] == 'P') {
					start = new Node(r, c);
				}
			}
		}
		
		int idx = 0;
		for(int r = 0 ; r < N ; ++r) {
			st = new StringTokenizer(br.readLine());
			for(int c = 0 ; c < N ; ++c) {
				heightMap[r][c] = stoi(st.nextToken());
				if(!heightList.contains(heightMap[r][c])) {
					heightList.add(heightMap[r][c]);
				}
			}
		}
		
		// 투 포인터를 사용하기 위해 오름차순 정렬 
		Collections.sort(heightList);
		
		System.out.println(solve());
	}
	
	private static int solve() {
		int min = 0;
		int max = 0;
		int ans = Integer.MAX_VALUE;
		
		while(min < heightList.size() && max < heightList.size()) {
			if(bfs(heightList.get(min), heightList.get(max))) {
				int gap = heightList.get(max) - heightList.get(min);
				ans = ans > gap ? gap : ans;
				
				// 탐색에 성공하면 min 값을 늘려 피로도를 줄여나간다. 
				min++;
			} else {
				// 탐색에 실패하면 max 값을 늘려 더 높은 피로도로 탐색할 수 있도록 한다.
				max++;
			}
		}
		
		return ans;
	}

	private static boolean bfs(int min, int max) {
		// 시작 지점이 min 보다 낮거나 max 보다 높으면 시작할 수 없다.
		int startH = heightMap[start.r][start.c];
		if(startH > max || startH < min) return false;
		
		int[][] dir = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
		Queue<Node> q = new LinkedList<>();
		boolean[][] visited = new boolean[N][N];
		int cnt = 0;
	
		q.offer(start);
		visited[start.r][start.c] = true;
		
		while(!q.isEmpty()) {
			Node now = q.poll();
			
			if(map[now.r][now.c] == 'K') cnt++;
			
			if(cnt == house) return true;
			
			for(int d = 0 ; d < 8 ; ++d) {
				int nr = now.r + dir[d][0];
				int nc = now.c + dir[d][1];
				
				if(nr >= N || nr < 0 || nc >= N || nc < 0 || visited[nr][nc]) continue;
				
				if(heightMap[nr][nc] >= min && heightMap[nr][nc] <= max) {
					visited[nr][nc] = true;
					q.offer(new Node(nr, nc));
				}
			}
		}

		return false;
	}

	private static int stoi(String s) {
		return Integer.parseInt(s);
	}
}
profile
그냥 개발자

0개의 댓글