[이것이 코딩 테스트다] 숨바꼭질
업데이트:
문제
문제의 저작권은 ‘이것이 코딩테스트다’ 교재에 있습니다.
동빈이는 숨바꼭질을 하면서 술래로부터 잡히지 않도록 숨을 곳을 찾고 있다. 동빈이는 1 ~ N번까지의 헛간 중에서 하나를 골라 숨을 수 있으며, 술래는 항상 1번 헛간에서 출발합니다. 전체 맵에는 총 M개의 양방향 통로가 존재하며, 하나의 통로는 서로 다른 두 헛간을 연결한다. 또한 전체 맵은 항상 어떤 헛간에서 다른 어떤 헛간으로 도달이 가능한 형태로 주어진다.
동빈이는 1번 헛간으로부터 최단 거리가 가장 먼 헛간이 가장 안전하다고 판단한다. 이때 최단 거리의 의미는 지나야 하는 길의 최소 개수를 의미한다. 동빈이가 숨을 헛간의 번호를 출력하는 프로그램을 작성하라
입력 조건
- 첫째 줄에는 N, M이 주어지며, 공백으로 구분한다.
- 2 <= N <= 20,000
- 1 <= M <= 50,000
- 이후 M개의 줄에 걸쳐서 서로 연결된 두 헛간 A와 B의 번호가 공백으로 구분되어 주어진다.
- 1 <= A, B <= N
출력 조건
1) 숨어야 하는 헛간 번호
- 거리가 같은 헛간이 여러개면 가장 작은 헛간 번호를 출력
2) 그 헛간까지의 거리
3) 그 헛간과 같은 거리를 갖는 헛간의 개수
입력 예시
6 7
3 6
4 3
3 2
1 3
1 2
2 4
5 2
출력 예시
4 2 3
접근방식
출발노드에서 도착노드까지의 최단거리를 먼저 구해야 하므로 다익스트라 알고리즘을 사용하였다.
1) pq를 사용해서 가장 최단거리가 짧은 노드 먼저 꺼내주고, 다음 노드와 비교해서 거쳐가는 경우가 더 짧으면 갱신 후 pq에 넣어주는 식으로 최단거리를 구해준다.
2) 다 구했으면 문제의 답은 최단거리가 가장 먼 헛간의 번호를 출력해주는것이므로 최단거리가 가장 먼 노드의 번호와 그때의 거리를 구하고, 이 거리와 같은 노드들의 개수를 출력한다.
import java.io.*;
import java.util.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int N, M; // 헛간 수(정점), 통로 수(간선)
static final int INF = 1000000000;
static ArrayList<Node>[] adjList; // 간선정보 저장
static int[] dist; // 최단거리 저장
static PriorityQueue<Node> pq;
static class Node implements Comparable<Node> {
int num, dist; // 정점 번호, 비용
public Node(int num, int dist) {
this.num = num;
this.dist = dist;
}
@Override
public int compareTo(Node o) { // 가중치 최소값 pop
return this.dist - o.dist;
}
}
public static void main(String[] args) throws IOException {
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
adjList = new ArrayList[N + 1];
for (int i = 1; i <= N; i++)
adjList[i] = new ArrayList<>();
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
adjList[x].add(new Node(y, 1));
adjList[y].add(new Node(x, 1));
}
dijkstra(); // 그래프 탐색
showAns(); // 답 구하기
}
private static void showAns() {
int maxNode = 0; // 최단 거리가 가장 먼 노드번호(여러개면 더 작은 번호)
int maxDist = -1; // 최단거리가 가장 먼 노드와의 최단거리
int maxCnt = 0; // maxNode와 거리가 같은 노드들의 개수
for (int i = 1; i <= N; i++) {
//if (dist[i] > maxDist) {
if (dist[i]!=INF &&dist[i] > maxDist) {
maxDist = dist[i];
maxNode = i;
}
}
for (int i = 1; i <= N; i++) {
if (maxDist == dist[i]) maxCnt++;
}
System.out.println(maxNode + " " + maxDist + " " + maxCnt);
}
private static void dijkstra() {
pq = new PriorityQueue<Node>(); // 최소 가중치 먼저 나옴
// 초기 세팅
pq.add(new Node(1, 0)); // 1번 노드부터 시작
dist = new int[N + 1];
Arrays.fill(dist, INF); // 최대값으로 세팅
dist[1] = 0;
while (!pq.isEmpty()) {
Node now = pq.poll(); // 가장 최단거리 노드 pop
if (now.dist > dist[now.num])
continue; // 이미 방문했던 노드면 pass
for (Node next : adjList[now.num]) { // 인접한 노드들 탐색
if (dist[next.num] > dist[now.num] + next.dist) { // 현재 노드에서 다른 노드를 거치는 거리가 더 짦으면 갱신
dist[next.num] = dist[now.num] + next.dist;
pq.add(new Node(next.num, dist[next.num]));
}
}
}
}
}