본문 바로가기

Programming/BOJ

BOJ 1260 · DFS와 BFS


알고리즘 분류 : DFS, BFS  


DFS와 BFS의 기초를 다질 수 있는 문제이다.


DFS(Depth-First Search)란 깊이 우선 탐색의 줄임말로, 그래프에서 완전 탐색을 할 때 깊이를 우선순위로 탐색하는 방법을 말한다. 스택(Stack) 자료구조에 방문한 노드를 저장하면서 깊이 우선 탐색을 진행한다. 스택 자료구조(반복문으로 구현) 대신 재귀로 구현할 수 있다. 재귀 함수로 구현하면 스택 메모리를 사용하므로, 메모리 오버헤드가 발생할 수 있다. 재귀를 통한 DFS 구현이 스택 자료구조를 통한 DFS 구현보다 좀 더 코드가 깔끔하고 구현이 용이한 편이다.

BFS(Breadth-First Search)란 너비 우선 탐색의 줄임말로, 그래프에서 완전 탐색을 할 때 너비를 우선순위로 탐색하는 방법을 말한다. 큐(Queue) 자료구조에 방문한 노드를 저장하면서 너비 우선 탐색을 진행한다.


  • 방법의 차이일 뿐, 모든 노드를 탐색한다면 둘 중 편한 것을 이용하면 된다. 단, 비가중치 그래프의 최단 경로 문제는 BFS를 이용해야 한다.
  • DFS, BFS는 인접 행렬이나 인접 리스트로 구현할 수 있다. 일반적으로 인접 리스트 구현이 공간/시간복잡도 면에서 효율적이다.
  • 두 방법 모두 하나의 노드는 한 번만 탐색하는 것을 원칙으로 하므로, 별도의 check 배열을 만들어서 방문 여부를 저장해야 한다.



C++ 소스코드 (인접 행렬)


#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

int n, m, v;
int a[1001][1001];
bool check[1001];

void dfs(int now) {
    check[now] = true;
    printf("%d ", now);
    for (int i=1; i<=n; i++) {
        if (a[now][i] &&!check[i]) {
            dfs(i);
        }
    }
}

void bfs(int v) {
    memset(check, false, sizeof(check));
    queue<int> q;
    q.push(v);
    check[v] = true;
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        printf("%d ", now);
        for (int i=1; i<=n; i++) {
            if (a[now][i] && !check[i]) {
                check[i] = true;
                q.push(i);
            }
        }
    }
}

int main() {
    scanf("%d %d %d", &n, &m, &v);
    for (int i=0; i<m; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        a[x][y] = 1;
        a[y][x] = 1;
    }
    dfs(v);
    printf("\n");
    bfs(v);
    printf("\n");
    return 0;
}


✓ queue는 STL에 있는 queue 라이브러리를 사용했다.

✓ memset을 통해 check를 false로 초기화했다. 먼저 DFS에서 방문체크를 했기 때문에, BFS에서 다시 사용하려면 초기화가 필요하다.

✓ 인접리스트 방식은 STL의 vector를 이용하면 된다.




Python 3 소스코드 (인접 행렬)


import sys
from collections import deque
n, m, v = map(int, sys.stdin.readline().split())
a = [[0 for _ in range(n+1)] for _ in range(n+1)]
c = [False] * (n+1)

def dfs(now):
    c[now] = True
    print(now, end=' ')
    for i in range(1, n+1):
        if a[now][i] == 1 and c[i] is False:
            dfs(i)

def bfs(v):
    c = [False] * (n+1)
    q = deque()
    q.append(v)
    c[v] = True
    while q:
        now = q.popleft()
        print(now, end=' ')
        for i in range(1, n+1):
            if a[now][i] == 1 and c[i] is False:
                c[i] = True
                q.append(i)

for _ in range(m):
    x, y = map(int, sys.stdin.readline().split())
    a[x][y] = 1
    a[y][x] = 1

dfs(v)
print()
bfs(v)
print()


✓ 입출력 속도 향상을 위해 input() 대신, sys.stdin.readline()을 사용했다.

✓ queue는 list를 써도 상관없지만, 연산이 많으면 collections의 deque이 더 효율적이다.




참고



태그