-
백준 18513번: 샘터 (Python/Java)Algorithm/Algorithm Problem 2022. 1. 11. 22:03
https://www.acmicpc.net/problem/18513
18513번: 샘터
첫째 줄에 자연수 N과 K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N, K ≤ 100,000) 둘째 줄에 N개의 샘터의 위치가 공백을 기준으로 구분되어 정수 형태로 주어진다. (-100,000,000 ≤ 샘터의 위치 ≤
www.acmicpc.net
접근
이 문제에서 물어보는 것은 불행도의 합이 가장 적은 방법으로 집을 위치시키고, 불행도를 구하라는 것이다. 문제만 읽어봐도 알 수 있듯이 말만 불행도라고 했지, 결국 샘터와 가장 가까운 집들의 거리합을 구하는 문제다.(애초에 문제에서 집의 불행도는 샘터와의 거리로 정의된다고 적어놨다) 가장 가까운 거리의 합을 구하는 전형적인 너비우선탐색 문제라고 볼 수 있다.
그렇다면 가장 가까운 거리의 합은 어떻게 구할까? 탐색에 사용할 큐에 모든 샘터들의 위치를 넣는다. 그리고 하나씩 꺼내 양 옆에 샘터, 혹은 집이 있는지 살펴보고 있다면 넘어가고 없다면 위치를 체크한 뒤 해당 위치를 큐에 넣어준다. 이를 반복하다 보면 구해야 하는 집의 수만큼 체크할 수 있을 것이고 그때 탐색을 끝낸 뒤, 거리 합을 출력하면 된다.
여기서 주의할 것이 샘터의 범위 조건이다. 샘터의 범위는 -100,000,000과 100,000,000 사이라고 나와있다. 다시 한번 말하지만 이는 샘터의 범위 조건이다. 집은 이 범위 밖을 벗어나도 상관없다. 이 문제는 집 위치 범위가 따로 없기 때문에 범위는 신경 쓰지 않아도 된다. 이 부분만 짚고 넘어가면 어렵지 않게 답을 맞힐 수 있다.
풀이
Python
from collections import deque waterNum, houseNum = map(int, (input()).split()) waterList = list(map(int, (input()).split())) visitList = {} bfsDeque = deque() for i in range(waterNum): visitList[waterList[i]] = True bfsDeque.append([waterList[i], 0]) leftRight = [-1, 1] result = 0 thisHouse = 0 while True: thisDeque = bfsDeque.popleft() for i in range(2): subIdx = (thisDeque[0] + leftRight[i]) if not subIdx in visitList: visitList[subIdx] = True bfsDeque.append([subIdx, (thisDeque[1]+1)]) thisHouse += 1 if thisHouse <= houseNum: result += (thisDeque[1] + 1) else: break if thisHouse >= houseNum: break print(result)
Java
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.HashMap; import java.util.LinkedList; import java.util.Queue; public class Main { static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); public static void main(String[] args) throws IOException{ String[] firstLine = (br.readLine()).split(" "); int waterNum = Integer.parseInt(firstLine[0]); int houseNum = Integer.parseInt(firstLine[1]); String[] secondLine = (br.readLine()).split(" "); HashMap<Integer, Boolean> visitList = new HashMap<Integer, Boolean>(); Queue<int[]> bfsQueue = new LinkedList<>(); for(int i = 0 ; i < waterNum ; i++){ visitList.put(Integer.parseInt(secondLine[i]), true); bfsQueue.add(new int[] {Integer.parseInt(secondLine[i]), 0}); } int[] leftRight = {-1, 1}; long result = 0; int thisHouse = 0; loop: while(true){ int[] thisQueue = bfsQueue.poll(); for(int i = 0 ; i < 2 ; i++){ int subIdx = (thisQueue[0] + leftRight[i]); if(!visitList.containsKey(subIdx)){ visitList.put(subIdx, true); bfsQueue.add(new int[] {subIdx, (thisQueue[1]+1)}); thisHouse++; if(thisHouse <= houseNum){ result += (thisQueue[1] + 1); }else{ break loop; } } } } System.out.println(result); } }
후기
요 근래 일주일 하고도 며칠 그리디 문제만 풀었더니 너비우선탐색이 땡겨 풀어봤다. 구현이 조금 복잡할 수는 있어도 역시 그래프 문제가 재밌긴 한 것 같다.
한 가지 찜찜한 부분이 있는데, 탐색 영역 체크 구현이다. 범위 조건이 따로 없는 문제다 보니 따로 배열을 만드는 방법 같은 것들은 사용할 수 없었다. 그렇다고 체크를 안 할 수는 없어 생각해낸 부분이 파이썬의 경우엔 dict를, 자바의 경우엔 hashmap을 사용한 것이었다. 탐색한 위치의 인덱스를 키 값으로 설정해 추가해주고 해당 키 값이 dict 혹은 hashmap에 있는지 없는지를 확인해 탐색 여부를 체크했다. 어쨌든 정답 처리가 되긴 했지만 이렇게 풀어도 되는지, 조금 더 좋은 방법이 있는지 생각해봐야겠다.
'Algorithm > Algorithm Problem' 카테고리의 다른 글
백준 14499번: 주사위 굴리기 (Python/Java) (0) 2022.01.13 백준 5427번: 불 (Python/Java) (0) 2022.01.12 백준 1092번: 배 (Python/Java) (0) 2022.01.10 백준 1461번: 도서관 (Python/Java) (0) 2022.01.09 백준 2212번: 센서 (Python/Java) (0) 2022.01.08