_06-3 너비 우선 탐색(BFS, Breadth-First Search)
그래프 탐색 알고리즘 중 **너비 우선 탐색(BFS, Breadth-First Search)**은 시작 노드에서 출발하여, 시작 노드와 가까운 노드부터 차례대로 방문하는 방식입니다.
깊이 우선 탐색(DFS)과 달리, BFS는 같은 레벨(거리)에 있는 노드들을 먼저 방문하기 때문에 최단 경로 탐색 등에 유용합니다.
1. BFS 특징
- 완전 탐색 방식
- 그래프의 모든 노드를 한 번씩 방문하여 탐색합니다.
- FIFO 자료구조 사용
- BFS는 방문할 노드를 순서대로 처리해야 하기 때문에 큐(Queue) 자료구조를 사용합니다.
- 큐는 선입선출(FIFO, First In First Out) 구조를 가지고 있어, 먼저 들어온 노드가 먼저 탐색됩니다.
- 최단 경로 탐색에 적합
- 가중치가 없는 그래프에서 시작 노드로부터 각 노드까지의 최단 거리를 구할 때 BFS를 활용할 수 있습니다.
2. BFS 동작 원리
- 시작 노드를 큐에 넣고 방문 처리합니다.
- 큐에서 노드를 하나 꺼내 현재 노드와 연결된 인접 노드들을 방문합니다.
- 방문하지 않은 인접 노드를 큐에 넣고 방문 처리합니다.
- 큐가 빌 때까지 2~3번 과정을 반복합니다.
3. BFS 순서 예시
- 시작 노드: A
- A와 연결된 노드 B, C를 큐에 넣고 방문
- 큐에서 B를 꺼내 B와 연결된 노드 D, E를 방문 후 큐에 추가
- 큐에서 C를 꺼내 C와 연결된 노드 F를 방문 후 큐에 추가
- 큐에서 D, E, F 순서로 꺼내며 탐색 완료
이 과정을 통해 같은 거리의 노드들이 먼저 방문되므로 레벨 순서 탐색이 가능합니다.
4. BFS 활용 예시
- 소셜 네트워크에서 친구 추천
- 지도나 길찾기에서 최단 경로 계산
- 퍼즐, 게임에서 최소 이동 횟수 계산
- 그래프의 연결 요소 확인
__[029] DFS와 BFS 프로그램
백준 온라인 져지 1260번 https://www.acmicpc.net/problem/1260
import java.io.*;
import java.util.*;
public class Main {
static int N, M, V;
static ArrayList<Integer>[] graph;
static boolean[] visitedDFS;
static boolean[] visitedBFS;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken()); // 정점 개수
M = Integer.parseInt(st.nextToken()); // 간선 개수
V = Integer.parseInt(st.nextToken()); // 시작 정점 번호
// 그래프 초기화
graph = new ArrayList[N + 1];
for (int i = 1; i <= N; i++) {
graph[i] = new ArrayList<>();
}
// 간선 정보 입력
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
graph[a].add(b);
graph[b].add(a); // 양방향
}
// 방문할 때 번호 작은 순서로 처리하기 위해 정렬
for (int i = 1; i <= N; i++) {
Collections.sort(graph[i]);
}
visitedDFS = new boolean[N + 1];
dfs(V); // DFS 수행
System.out.println();
visitedBFS = new boolean[N + 1];
bfs(V); // BFS 수행
}
// 깊이 우선 탐색
static void dfs(int v) {
visitedDFS[v] = true;
System.out.print(v + " ");
for (int next : graph[v]) {
if (!visitedDFS[next]) {
dfs(next);
}
}
}
// 너비 우선 탐색
static void bfs(int start) {
Queue<Integer> queue = new LinkedList<>();
queue.add(start);
visitedBFS[start] = true;
while (!queue.isEmpty()) {
int v = queue.poll();
System.out.print(v + " ");
// queue에 인접 노드를 넣기 전에 주석 처리 가능
for (int next : graph[v]) {
// 아직 방문하지 않은 노드만 추가
if (!visitedBFS[next]) {
queue.add(next); // 큐에 넣음 → 나중에 방문할 예정
visitedBFS[next] = true; // 방문 체크 미리 함 → 중복 enqueue 방지
}
}
}
}
}
__[030] 미로 탐색하기
백준 온라인 져지 2178번 https://www.acmicpc.net/problem/2178
import java.util.*;
import java.io.*;
public class Main {
// 상, 하, 좌, 우 이동을 위한 좌표 배열
static int[] dx = {-1, 1, 0, 0};
static int[] dy = {0, 0, -1, 1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()); // 미로 세로 크기
int M = Integer.parseInt(st.nextToken()); // 미로 가로 크기
int[][] maze = new int[N][M]; // 미로 배열
boolean[][] visited = new boolean[N][M]; // 방문 여부 체크
// 미로 입력 받기
for (int i = 0; i < N; i++) {
String line = br.readLine();
for (int j = 0; j < M; j++) {
maze[i][j] = line.charAt(j) - '0'; // '1' -> 1, '0' -> 0
}
}
// BFS 탐색 시작
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{0, 0}); // 시작점 (0,0)
visited[0][0] = true;
// 시작점은 이미 지나간 칸 1
int[][] distance = new int[N][M];
distance[0][0] = 1;
while (!queue.isEmpty()) {
int[] current = queue.poll();
int x = current[0];
int y = current[1];
// 상하좌우 이동
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 미로 범위 밖이면 패스
if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
// 이동할 수 없는 칸이거나 이미 방문한 칸이면 패스
if (maze[nx][ny] == 0 || visited[nx][ny]) continue;
// 이동 가능하면 큐에 넣고 거리 갱신
queue.add(new int[]{nx, ny});
visited[nx][ny] = true;
distance[nx][ny] = distance[x][y] + 1;
}
}
// 도착점(N-1, M-1)까지의 최소 칸 수 출력
System.out.println(distance[N-1][M-1]);
}
}
__[031] 트리의 지름 구하기
백준 온라인 져지 1167번 https://www.acmicpc.net/problem/1167
import java.io.*;
import java.util.*;
public class Main {
static ArrayList<Node>[] tree;
static boolean[] visited;
static int maxDistance; // 가장 긴 거리
static int farthestNode; // 가장 먼 노드 번호
static class Node {
int vertex;
int weight;
Node(int vertex, int weight) {
this.vertex = vertex;
this.weight = weight;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int V = Integer.parseInt(br.readLine());
// 트리 초기화
tree = new ArrayList[V + 1];
for (int i = 1; i <= V; i++) {
tree[i] = new ArrayList<>();
}
// 입력 받기
for (int i = 0; i < V; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
int from = Integer.parseInt(st.nextToken());
while (true) {
int to = Integer.parseInt(st.nextToken());
if (to == -1) break; // -1이면 입력 종료
int weight = Integer.parseInt(st.nextToken());
tree[from].add(new Node(to, weight));
}
}
// 1. 임의의 노드(1번)에서 가장 먼 노드를 찾는다.
visited = new boolean[V + 1];
maxDistance = 0;
farthestNode = 0;
bfs(1);
// 2. 그 노드에서 다시 BFS를 수행하여 가장 먼 거리 = 트리의 지름
visited = new boolean[V + 1]; // 방문 초기화
maxDistance = 0;
bfs(farthestNode);
// 트리의 지름 출력
System.out.println(maxDistance);
}
static void bfs(int start) {
Queue<Node> q = new LinkedList<>();
q.add(new Node(start, 0));
visited[start] = true;
while (!q.isEmpty()) {
Node cur = q.poll();
// 현재까지의 거리와 최대 거리 비교
if (cur.weight > maxDistance) {
maxDistance = cur.weight;
farthestNode = cur.vertex;
}
// 인접 노드 탐색
for (Node next : tree[cur.vertex]) {
if (!visited[next.vertex]) {
visited[next.vertex] = true;
q.add(new Node(next.vertex, cur.weight + next.weight));
}
}
}
}
}'Do it! 알코테 자바' 카테고리의 다른 글
| [Do it] 알코테 자바 10일차 (0) | 2026.03.06 |
|---|---|
| [Do it] 알코테 자바 8일차 (0) | 2026.03.04 |
| [Do it] 알코테 자바 7일차 (0) | 2026.03.03 |
| [Do it] 알코테 자바 6일차 (0) | 2026.03.02 |
| [Do it] 알코테 자바 5일차 (0) | 2026.02.27 |