📌 문제
https://www.acmicpc.net/problem/1260
⭐ 정답코드
import java.io.*;
import java.util.*;
public class Main{
static boolean[][] a;
static boolean[] visited;
static StringBuilder sb = new StringBuilder();
static int n;
static Queue<Integer> q = new LinkedList<>();
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());
n = Integer.parseInt(st.nextToken());
int e = Integer.parseInt(st.nextToken());
int start = Integer.parseInt(st.nextToken());
a = new boolean[n+1][n+1];
visited = new boolean[n+1];
for (int i = 0; i<e; i++){
st = new StringTokenizer(br.readLine());
int node1 = Integer.parseInt(st.nextToken());
int node2 = Integer.parseInt(st.nextToken());
a[node1][node2] = true;
a[node2][node1] = true;
}
dfs(start);
sb.append("\n");
visited = new boolean[n+1];
bfs(start);
bw.write(sb.toString());
bw.flush();
bw.close();
br.close();
}
public static void dfs(int start){
sb.append(start+" ");
visited[start] = true;
for (int i = 1; i<=n; i++){
if (!visited[i] && a[start][i]) {
dfs(i);
}
}
}
public static void bfs(int start){
q.add(start);
visited[start] = true;
while (!q.isEmpty()){
start = q.poll();
sb.append(start+" ");
for (int i = 1; i<=n; i++){
if (!visited[i] && a[start][i]){
q.add(i);
visited[i] = true;
}
}
}
}
}
✅ 그래프 구성
그래프는 인접 행렬(boolean[][] a)을 사용하여 표현됩니다. 이 행렬에서 a[i][j]가 true이면 정점 i와 정점 j가 연결되어 있음을 의미합니다. 방문 여부는 visited[] 배열로 관리합니다.
✅ DFS
DFS는 후입선출 방식으로 작동합니다.
즉, 가장 최근에 방문한 정점을 먼저 탐색합니다.
구현 방식은 재귀 호출을 사용하여 깊이 깊이 탐색해 나갑니다.
⏹️ 과정
- 시작 정점 방문:
- dfs(start) 함수가 호출되면 현재 정점을 방문하고, 방문한 정점을 결과에 추가합니다.
- 예를 들어, 시작 정점이 1이라면 결과는 1이 됩니다.
- 이웃 정점 탐색:
- 현재 정점의 모든 이웃을 확인합니다.
- 이웃 정점 중에서 아직 방문하지 않은 정점이 있다면, 그 정점으로 재귀 호출을 합니다.
- 재귀 호출:
- 예를 들어, 1의 이웃 정점이 2, 3, 4라면, DFS는 가장 작은 정점인 2로 이동합니다.
- 이제 dfs(2)를 호출하게 되고, 방문 상태로 표시한 후 결과에 2를 추가합니다.
- 탐색 깊이:
- 현재 정점 2에서 또 이웃을 탐색합니다. 예를 들어, 2의 이웃이 3, 4라고 가정하면 DFS는 다음으로 3으로 이동합니다.
- 이 과정이 반복되어, 더 이상 갈 수 없는 정점에 도달하면, 호출 스택이 되돌아가면서 이전 정점으로 돌아옵니다.
- 되돌아가기:
- DFS는 재귀적으로 깊이 들어간 후에 더 이상 갈 곳이 없으면 호출 스택을 따라 올라가면서, 그 경로를 되돌아가게 됩니다.
- 이로 인해 DFS는 가장 깊은 정점부터 탐색을 종료하게 됩니다.
✅ BFS
BFS는 선입선출 방식으로 작동합니다.
즉, 먼저 큐에 들어간 정점이 먼저 탐색됩니다.
큐를 사용하여 현재 정점의 이웃을 탐색하고, 이웃들을 모두 큐에 추가한 후 하나씩 꺼내어 탐색합니다.
⏹️ 과정
- 시작 정점 추가:
- bfs(start) 함수를 호출하면 시작 정점을 큐에 추가합니다.
- 예를 들어, 시작 정점이 1이라면 큐에는 [1]이 됩니다.
- 이때, 정점 1은 방문 상태로 표시됩니다.
- 큐에서 정점 꺼내기:
- 큐에서 정점을 하나 꺼내는 작업은 가장 먼저 들어간 정점부터 꺼내는 방식입니다.
- 위의 예에서 큐에서 1을 꺼내면, 이제 큐는 비어있습니다: [].
- 이웃 정점 추가:
- 꺼낸 정점(여기서는 1)의 이웃을 확인하고, 아직 방문하지 않은 정점들을 큐에 추가합니다.
- 만약 1과 연결된 정점이 2, 3, 4라면, 이 정점들을 큐에 추가합니다. 이제 큐는 [2, 3, 4]가 됩니다.
- 여기서 방문한 정점 2, 3, 4도 표시해줍니다.
- 반복:
- 큐가 빌 때까지 이 과정을 반복합니다. 큐의 첫 번째 정점을 계속 꺼내어, 그 정점의 이웃을 큐에 추가하는 방식입니다.
- 큐에서 꺼내는 순서는 다음과 같습니다:
- 2 꺼내기: 큐는 [3, 4]가 되고, 2의 이웃 정점(예를 들어 5, 6)을 큐에 추가하면 [3, 4, 5, 6]이 됩니다.
- 3 꺼내기: 큐는 [4, 5, 6]가 되고, 3의 이웃 정점(예를 들어 7)을 큐에 추가하면 [4, 5, 6, 7]이 됩니다.
- 4 꺼내기: 큐는 [5, 6, 7]가 되고, 4의 이웃을 추가합니다.
🚩 결론
DFS는 후입선출 방식으로 깊이 탐색하고, BFS는 선입선출 방식으로 너비 탐색을 합니다.
이 차이로 인해 각각의 탐색 방식이 그래프에서 다르게 동작하며, 방문하는 정점의 순서도 달라지게 됩니다.
DFS는 주로 경로를 찾거나 트리 구조를 깊이 탐색할 때 유용하고, BFS는 최단 경로를 찾거나 넓은 범위의 탐색이 필요할 때 효과적입니다.
'코딩 테스트 일지 📒' 카테고리의 다른 글
[프로그래머스] 여행 경로 | DFS, BFS | Level.3 | JAVA (3) | 2024.10.11 |
---|---|
[시스템 아키텍처] 컨테이너화: 현대 소프트웨어 배포의 혁신 (0) | 2024.10.11 |
[백준]1697 숨바꼭질 | 그래프, BFS | 실버 Ⅰ | JAVA (0) | 2024.10.10 |
[알고리즘] DFS와 BFS (2) | 2024.10.10 |
[프로그래머스] 타겟 넘버 | DFS, BFS | Level.2 | JAVA (0) | 2024.10.08 |