내 학점 (C++)

[C++] DFS & BFS

z_zen 2025. 12. 16. 00:09
728x90

그래프 탐색은 크게 두 가지 방식이 있다.

  • DFS (Depth First Search) : 깊이 우선 탐색
  • BFS (Breadth First Search) : 너비 우선 탐색

그래프란?

정점(Vertex)과 간선(Edge)으로 이루어진 구조

  • 정점: 노드
  • 간선: 노드와 노드를 연결하는 선

🔍 DFS (깊이 우선 탐색)

✔ 개념

한 방향으로 갈 수 있을 때까지 끝까지 내려갔다가, 막히면 되돌아오는 방식

 

마치 미로 탐색처럼 동작한다.

✔ DFS 탐색 순서 예시

1 → 2 → 4 → (더 못 감) → 3 → 5

 

✔ DFS 특징

  • 재귀 또는 스택으로 구현
  • 한 경로를 깊게 탐색
  • 백트래킹 문제에서 자주 사용

✔ DFS 사용 예

  • 경로 존재 여부
  • 조합, 순열
  • 미로 탐색
  • 트리 순회

DFS 구현 (재귀)

vector<vector<int>> graph;
vector<bool> visited;

void dfs(int v) {
    visited[v] = true;
    cout << v << " ";

    for (int next : graph[v]) {
        if (!visited[next]) {
            dfs(next);
        }
    }
}

🔍 BFS (너비 우선 탐색)

✔ 개념

현재 위치에서 갈 수 있는 곳을 먼저 전부 탐색한 뒤, 다음 단계로 넘어가는 방식

 

물결처럼 퍼져나가는 탐색

✔ BFS 탐색 순서 예시

1 → 2 → 3 → 4 → 5

 

✔ BFS 특징

  • 큐(queue) 사용
  • 가까운 정점부터 탐색
  • 최단 거리 문제에 최적

✔ BFS 사용 예

  • 최단 거리
  • 레벨 탐색
  • 시작점에서 최소 이동 횟수

BFS 구현 (큐)

void bfs(int start) {
    queue<int> q;
    visited[start] = true;
    q.push(start);

    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        cout << cur << " ";

        for (int next : graph[cur]) {
            if (!visited[next]) {
                visited[next] = true;
                q.push(next);
            }
        }
    }
}

예제 그래프

정점은 1부터 5까지이며, 시작 정점은 1이다.
번호가 작은 정점부터 방문한다고 가정한다.

    1
   / \
  2   3
   \   \
    4   5

간선:

  • 1 - 2
  • 1 - 3
  • 2 - 4
  • 3 - 5

DFS (Depth First Search)

개념

DFS는 한 방향으로 갈 수 있을 때까지 끝까지 이동한 뒤, 더 이상 갈 수 없으면 되돌아오는 방식이다.
재귀 호출이나 스택을 사용한다.

DFS 탐색 과정

1단계

  • 시작 정점 1 방문
방문: 1

 

2단계

  • 1에서 갈 수 있는 가장 작은 정점 → 2
방문: 2

 

3단계

  • 2에서 갈 수 있는 정점 → 4
방문: 4

 

4단계

  • 4는 더 이상 갈 곳이 없음 → 되돌아감

5단계

  • 2도 더 이상 갈 곳이 없음 → 되돌아감

6단계

  • 1에서 아직 방문하지 않은 정점 → 3
방문: 3

 

7단계

  • 3에서 갈 수 있는 정점 → 5
방문: 5

DFS 최종 방문 순서

1 → 2 → 4 → 3 → 5

BFS (Breadth First Search)

개념

BFS는 현재 위치에서 갈 수 있는 모든 정점을 먼저 방문한 뒤, 다음 단계로 이동한다.
큐(queue)를 사용한다.

BFS 탐색 과정

1단계

  • 시작 정점 1 방문
  • 큐에 1 삽입
큐: [1]

 

2단계

  • 1에서 갈 수 있는 정점 모두 방문 (2, 3)
큐: [2, 3]

 

3단계

  • 2를 꺼내고, 갈 수 있는 정점 4 방문
큐: [3, 4]

 

4단계

  • 3을 꺼내고, 갈 수 있는 정점 5 방문
큐: [4, 5]

 

5단계

  • 4, 5는 더 이상 갈 곳이 없음
  • 큐가 비면 종료

BFS 최종 방문 순서

1 → 2 → 3 → 4 → 5

DFS와 BFS 비교

구분DFSBFS

탐색 방식 깊이 우선 너비 우선
사용 자료구조 스택 / 재귀
최단 거리 보장 X 보장 O
탐색 특징 한 경로 집중 레벨 단위 탐색

언제 어떤 탐색을 사용할까?

DFS 사용 상황

  • 모든 경우를 탐색해야 할 때
  • 경로 존재 여부
  • 조합, 순열, 백트래킹 문제

BFS 사용 상황

  • 최단 거리 문제
  • 최소 이동 횟수
  • 단계별 탐색이 필요한 경우

백준 1260 (DFS와 BFS) 전체 코드 예제

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

vector<vector<int>> graph;
vector<bool> visited;

void dfs(int v) {
    visited[v] = true;
    cout << v << " ";

    for (int next : graph[v]) {
        if (!visited[next]) {
            dfs(next);
        }
    }
}

void bfs(int start) {
    queue<int> q;
    visited[start] = true;
    q.push(start);

    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        cout << cur << " ";

        for (int next : graph[cur]) {
            if (!visited[next]) {
                visited[next] = true;
                q.push(next);
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M, V;
    cin >> N >> M >> V;

    graph.resize(N + 1);
    visited.resize(N + 1, false);

    for (int i = 0; i < M; i++) {
        int a, b;
        cin >> a >> b;
        graph[a].push_back(b);
        graph[b].push_back(a);
    }

    // 작은 번호부터 방문하기 위해 정렬
    for (int i = 1; i <= N; i++) {
        sort(graph[i].begin(), graph[i].end());
    }

    // DFS
    dfs(V);
    cout << '\n';

    // 방문 배열 초기화
    fill(visited.begin(), visited.end(), false);

    // BFS
    bfs(V);
    cout << '\n';

    return 0;
}
728x90