https://www.acmicpc.net/problem/24444
알고리즘의 기본이라고 알고있는 DFS, BFS 중 BFS 문제를 풀어보았다.
이 문제를 풀면서 필수적이라고 생각했던 부분
1. 방문여부를 기억하는 것
2. 양방향 간선이기 때문에 '시작정점의 리스트에 끝정점을 추가'하고 반대로 '끝정점의 리스트에 시작정점을 추가'
3. 방문순서를 기억하는 배열의 인덱스가 곧 정점이다.
- 방문이동횟수를 카운트 하여 몇번 정점에 몇번째로 방문했는지 데이터 삽입.
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
int R = Integer.parseInt(st.nextToken());
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i <= N; i++){
graph.add(new ArrayList<>()); // 각 정점에 대해 빈 리스트를 추가하여 그래프의 인접 리스트를 초기화합니다.
}
for (int i=0; i< M; i++){ // M 개의 간선을 입력받아 그래프에 추가
st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
graph.get(u).add(v); // 시작 정점 u의 리스트에 끝 정점 v를 추가한다.
graph.get(v).add(u); // 끝 정점 v의 리스트에 시작 정점 u를 추가한다.
}
for(int i=1; i<=N; i++){
Collections.sort(graph.get(i)); // 각 정점의 인접 리스트를 오름차순으로 정렬
}
boolean[] visited = new boolean[N+1]; // 방문 여부를 저장하는 배열 // 정점 번호가 1부터 시작하므로 크기는 N+1
int[] order = new int[N+1]; // 방문 순서를 기록할 배열, 초기값은 0 // order의 인덱스를 node로 가정
Queue<Integer> q = new LinkedList<>(); // BFS 탐색을 위한 큐
q.add(R); // 시작 정점 R을 큐에 추가한다.
visited[R] = true; // 시작 정점 R을 방문했음을 표시
int visitOrder = 1; // 첫번째 방문이기 때문에 1로 시작
order[R] = visitOrder++; // 첫번째 방문(1)이후 visitOrder 2로 세팅
while(!q.isEmpty()){
int node = q.poll();
for(int next : graph.get(node)) { // 현재 정점에 인접한 모든 정점을 탐색
if(!visited[next]){
visited[next] = true;
q.add(next);
order[next] = visitOrder++; // 방문 후 visitOrder 1씩 추가 //방문 순서를 ++해가면서 순서를 설정
}
}
}
// 방문한 정점을 출력 // order의 인덱스가 정점. 해당 정점을 몇번째에 방문했는지가 출력값
for (int i=1; i<=N; i++) { // 5번 인덱스 까지 있기 때문에 '<='이다.
if(i==N){
bw.write(String.valueOf(order[i]));
} else {
bw.write(order[i] + "\n");
}
}
bw.flush();
}
}
코드 실행 과정
1. 그래프 초기화
- 'graph' 리스트를 생성하고 각 정점에 대해 빈 리스트를 추가
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i <= N; i++) {
graph.add(new ArrayList<>());
}
2. 간선 입력
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
graph.get(u).add(v);
graph.get(v).add(u);
}
- 간선 입력 후 'graph' 리스트
graph[0] = []
graph[1] = [4, 2]
graph[2] = [3, 4, 1]
graph[3] = [4, 2]
graph[4] = [1, 2, 3]
graph[5] = []
3. 그래프 정렬
for (int i = 1; i <= N; i++) {
Collections.sort(graph.get(i));
}
- 그래프 정렬 후 'graph' 리스트
graph[0] = []
graph[1] = [2, 4]
graph[2] = [1, 3, 4]
graph[3] = [2, 4]
graph[4] = [1, 2, 3]
graph[5] = []
4. BFS 탐색 초기화
boolean[] visited = new boolean[N + 1];
int[] order = new int[N + 1];
Queue<Integer> q = new LinkedList<>();
q.add(R);
visited[R] = true;
int visitOrder = 1;
order[R] = visitOrder++;
- 초기상태
visited = [false, true, false, false, false, false]
order = [0, 1, 0, 0, 0, 0]
q = [1]
visitOrder = 2
5. BFS 탐색과정
- BFS 탐색을 진행하면서 큐가 비어있지 않을 때까지 다음을 반복
while (!q.isEmpty()) {
int node = q.poll();
for (int next : graph.get(node)) {
if (!visited[next]) {
visited[next] = true;
q.add(next);
order[next] = visitOrder++;
}
}
}
정점 1 방문
- node = q.poll() 결과: node = 1
- graph.get(1) 결과: [2, 4]
- 방문 상태:
visited = [false, true, true, false, true, false]
order = [0, 1, 2, 0, 3, 0]
q = [2, 4]
visitOrder = 4
정점 2 방문
- node = q.poll() 결과: node = 2
- graph.get(2) 결과: [1, 3, 4]
- 정점 1은 이미 방문됨, 정점 4도 이미 방문됨, 정점 3은 방문되지 않음
- 방문 상태:
visited = [false, true, true, true, true, false]
order = [0, 1, 2, 4, 3, 0]
q = [4, 3]
visitOrder = 5
정점 4 방문
- node = q.poll() 결과: node = 4
- graph.get(4) 결과: [1, 2, 3]
- 모두 이미 방문됨
- 방문 상태는 변하지 않음:
visited = [false, true, true, true, true, false]
order = [0, 1, 2, 4, 3, 0]
q = [3]
visitOrder = 5
정점 3 방문
- node = q.poll() 결과: node = 3
- graph.get(3) 결과: [2, 4]
- 모두 이미 방문됨
- 방문 상태는 변하지 않음:
visited = [false, true, true, true, true, false]
order = [0, 1, 2, 4, 3, 0]
q = []
visitOrder = 5
6. 결과출력
- order 배열을 순회하며 방문 순서를 출력
for (int i=1; i<=N; i++) {
if(i==N){
bw.write(String.valueOf(order[i])); // 마지막 순서 줄바꿈 제거
} else {
bw.write(order[i] + "\n");
}
}
bw.flush();
- 출력
1
2
4
3
0
'JAVA STUDY > 백준' 카테고리의 다른 글
백준 7576 - 토마토 (0) | 2024.06.05 |
---|