https://www.acmicpc.net/problem/9372
* 문제 요약
상근이는 겨울방학을 맞아 N개국을 여행하면서 자아를 찾기로 마음먹었다.
하지만 상근이는 새로운 비행기를 무서워하기 때문에, 최대한 적은 종류의 비행기를 타고 국가들을 이동하려고 한다.
이번 방학 동안의 비행 스케쥴이 주어졌을 때, 상근이가 가장 적은 종류의 비행기를 타고 모든 국가들을 여행할 수 있도록 도와주자.
상근이가 한 국가에서 다른 국가로 이동할 때 다른 국가를 거쳐 가도 (심지어 이미 방문한 국가라도) 된다.
* 입력
첫 번째 줄에는 테스트 케이스의 수 T (T <= 100) 가 주어지고, 각 테스트 케이스마다 다음과 같은 정보가 주어진다.
- 첫 번째 줄에는 국가의 수 N(2 <= N <= 1,000) 과 비행기의 종류 M (1 <= M <= 10,000) 가 주어진다.
- 이 후 M개의 줄에 a와 b쌍들이 입력된다. a와 b를 왕복하는 비행기가 있다는 것을 의미한다. (1 <= a, b <= n; a != b)
- 주어지는 비행 스케쥴은 항상 연결 그래프를 이룬다.
* 출력
테스트 케이스마다 한 줄을 출력한다.
- 상근이가 모든 국가를 여행하기 위해 타야 하는 비행기 종류의 최소 갯수를 출력한다.
* 예시
* 해결 과정
입력받은 각 종류의 왕복가능한 비행기들을 이용해서 갈 수 있는 모든 국가들을 방문하는데 있어 비행기를 최소로 이용하는 경우. 즉, 노드 별로 이어져 있는 양방향 그래프에서 모든 노드를 방문할 수 있는 최단 경로를 구하되 시작 지점을 제외한 각 노드를 방문할 때 지나가게 되는 그래프의 간선 갯수를 구하면 되는 문제이다.
최단 거리를 구하면 되는 문제이므로 BFS(너비 우선탐색) 을 활용하였다.
1. 해시맵과 큐를 활용해서 인접리스트 방식으로 BFS 알고리즘을 구현한다.
2. BFS 탐색을 수행할 때 첫 시작점은 입력받은 국가들의 값들 중에서 가장 작은 값으로 한다.
3. 만약 방문이 필요한 노드들이 저장된 큐(needVisit) 에서 꺼낸 값이 시작점과 같은 값인 경우 건너뛰고 아닐 경우 비행기 이용횟수 값을 1 증가시켜준다.
4. 해시맵에서 현재 방문 필요 큐에서 꺼낸 국가와 연결된 큐가 존재할 경우, 그 큐를 꺼내와서 안에 들어있는 값들을 하나씩 꺼내어 boolean 배열을 통해 아직 방문하지 않은 곳인지 확인하고 아직 방문하지 않은 곳인 경우 방문 필요 큐에 저장한다음 boolean 배열에서 해당 국가값에 해당하는 인덱스를 true 로 변환시켜 방문 표시를 해준다.
5. 방문 필요 큐가 완전히 빌 때까지 반복문이 진행되고 나면 최종적으로 비행기 이용 횟수값을 반환해준다.
* 코드
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 {
public static void main(String[] args) throws NumberFormatException, IOException {
new Main().solution();
}
static HashMap<Integer, Queue<Integer>> hashMap;
static boolean[] visited;
private void solution() throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int tc = Integer.parseInt(br.readLine());
for(int i = 0; i < tc; i++){
hashMap = new HashMap<>(); // 테스트 케이스마다 그래프 초기화
String[] input = br.readLine().split(" ");
int n = Integer.parseInt(input[0]); // 국가 숫자
int m = Integer.parseInt(input[1]); // 왕복 비행기 종류
visited = new boolean[n + 1];
int min = Integer.MAX_VALUE;
for(int j = 0; j < m; j++){
input = br.readLine().split(" ");
int a = Integer.parseInt(input[0]);
int b = Integer.parseInt(input[1]);
min = Math.min(min, a);
min = Math.min(min, b);
// 그래프 구조 저장
Queue<Integer> queueA = new LinkedList<>();
if(hashMap.containsKey(a)){
queueA = hashMap.get(a);
queueA.offer(b);
hashMap.put(a, queueA);
} else {
queueA.offer(b);
hashMap.put(a, queueA);
}
Queue<Integer> queueB = new LinkedList<>();
if(hashMap.containsKey(b)){
queueB = hashMap.get(b);
queueB.offer(a);
hashMap.put(b, queueB);
} else {
queueB.offer(a);
hashMap.put(b, queueB);
}
}
bw.write(bfs(min) + "\n");
}
bw.flush();
bw.close();
br.close();
}
private int bfs(int start) {
Queue<Integer> needVisit = new LinkedList<>();
needVisit.offer(start);
visited[start] = true;
int visitCount = 0;
while(!needVisit.isEmpty()){
int country = needVisit.poll();
if(country != start){
visitCount++;
}
Queue<Integer> queue = hashMap.get(country);
if(queue.size() > 0){
while(!queue.isEmpty()){
int needVisitCountry = queue.poll();
if(!visited[needVisitCountry]){
needVisit.offer(needVisitCountry);
visited[needVisitCountry] = true;
}
}
}
}
return visitCount;
}
}
최단 경로를 구할 때 그래프에서 지나치게 되는 간선의 갯수를 알아내면 되는 문제이다.
인접리스트 방식의 BFS 알고리즘을 구현할 줄 알면 쉽게 풀 수 있다.
'코딩 테스트 > 그래프' 카테고리의 다른 글
백준 2606 - 바이러스 (자바 - 그래프) (0) | 2023.07.12 |
---|---|
백준 14397 - 해변 (자바 - 그래프) (0) | 2023.07.12 |
백준 1388 - 바닥 장식 (자바 - 그래프) (0) | 2023.07.09 |
백준 2250 - 트리의 높이와 너비 (자바 - 그래프(트리) 탐색) (0) | 2021.12.26 |
백준 1939 - 중량 제한(자바 - BFS 및 이진탐색) (0) | 2021.12.21 |