카테고리 없음

DFS (깊이 우선탐색)

dmscks3126 2024. 9. 11. 13:52

DFS (깊이 우선탐색)

더보기
  • 비선형구조인 그래프 구조는 그래프로 표현된 모든 자료를 빠짐없이 검색하는 것이 중요함.
  • 두 가지 방법
    • 깊이 우선 탐색
    • 너비 우선 탐색

 

  • 시작 정점의 한 방향으로 갈 수 있는 경로가 있는 곳까지 깊이 탐색해 가다가 더 이상 갈 곳이 없게 되면,
    가장 마지막에 만났던 갈림길 간선이 있는 정점으로 되돌아와서 다른 방향의 정점으로 탐색을 계속 반복하여
    결국 모든 정점을 방문하는 순회방법
  • 가장 마지막에 만났던 갈림길의 정점으로 되돌아가서 다시 깊이 우선 탐색을 반복해야 하므로 후입선출 구조의 스택 사용

 

DFS 알고리즘 (수도코드)

더보기
visited[], stack[] 초기화
DFS(v)
    시작점 v 방문;
    visited[v] <- ture:
    while{
        if (v의 인접 정점 중 방문 안 한 정점 w가 있으면)
        push(v);
        v <- w; (w에 방문)
        visited[w] <- ture;
    else
        if (스택이 비어있지 않으면)
            v <- pop(stack);
        else
            break
    }
    end DFS()

 

DFS 예

더보기
  • 초기상태 : 배열 visited를 False로 초기화하고, 공백 스택을 생성

 

1) 정점 A를 시작으로 깊이 우선 탐색을 시작

A 방문;
    visited[A] <- true;

 

 

2) 정점 A에 방문하지 않은 정점 B, C가 있으므로 A를 스택에 push 하고, 

인접정점 B와 C 중에서 오름차순에 따라 B를 선택하여 탐색을 계속한다.

push(A);
B 방문;
visited[B] <- true;

 

3) 정점 B에 방문하지 않은 정점 D,E가 있으므로 B를 스택에 push 하고, 인접정점 D와 E 중에서 오름차순에 따라
D를 선택하여 탐색을 계속한다.

push(B);
D 방문;
visited[D] <- true;

 

4) 정점 D에 방문하지 않은 정점 F가 있으므로 D를 스택에 push 하고, 인접정점 F를 선택하여 탐색을 계속한다.

push(D);
F 방문;
visited[F] <- true;

 

5) 정점 F에 방문하지 않은 정점 E, G가 있으므로  F를 스택에 push 하고, 인접정점 E와 G중에서 오름차순에 따라
E를 선택하여 탐색을 계속한다.

push(F);
E 방문;
visited[E] <- true;

 

6) 정점 E에 방문하지 않은 정점 C가 있으므로 E를 스택에 push 하고, 인접정점 C를 선택하여 탐색을 계속한다.

push(E);
C 방문;
visited[C] <- true;

 

7) 정점 C에서 방문하지 않은 인접정점이 없으므로, 마지막 정점으로 돌아가기 위해 스택을 pop 하여 받은 정점 E에 대해서 방문하지 않은 인접정점이 있는지 확인한다. 

pop(stack);

 

8) 정점 E는 방문하지 않은 인접정점이 없으므로, 다시 스택을 pop하여 받은 정점 F에 대해서 방문하지 않은
인접정점이 있는지 확인한다. 

pop(stack);

 

9) 정점 F에 방문하지 않은 정점 G가 있으므로 F를 스택에 push 하고, 인접정점 G를 선택하여 탐색을 계속한다.

push(F);
G 방문;
visited[G] <- true;

 

10) 정점 G에서 방문하지 않은 인접정점이 없으므로, 마지막 정점으로 돌아가기 위해 스택을 pop하여 받은 
정점 F에 대해서 방문하지 않은 인접정점이 있는지 확인한다. 

pop(stack);

 

11) 정점 F에서 방문하지 않은 인접정점이 없으므로, 마지막 정점으로 돌아가기 위해 스택을 pop하여 받은 
정점 D에 대해서 방문하지 않은 인접정점이 있는지 확인한다. 

pop(stack);

 

12) 정점 D에서 방문하지 않은 인접정점이 없으므로, 마지막 정점으로 돌아가기 위해 스택을 pop하여 받은 
정점 B에 대해서 방문하지 않은 인접정점이 있는지 확인한다. 

pop(stack);

 

13) 정점 B에서 방문하지 않은 인접정점이 없으므로, 마지막 정점으로 돌아가기 위해 스택을 pop하여 받은 
정점 A에 대해서 방문하지 않은 인접정점이 있는지 확인한다. 

pop(stack);

 

14) 현재 정점 A에서 방문하지 않은 인접정점이 없으므로, 마지막 정점으로 돌아가기 위해 스택을 pop하는데, 
스택이 공백이므로 깊이 우선 탐색을 종료한다.

 

깊이 우선 탐색 경로 : A - B - D - F - E - C - G

 

<연습문제3>

더보기
  • 다음은 연결되어 있는 두 개의 정점 사이의 간선을 순서대로 나열해 놓은 것이다. 
    모든 정점을 깊이 우선 탐색하여 화면에 깊이 우선 탐색 경로를 출력하시오.
    시작 정점을 1로 시작하시오. 

 

[코드]

'''
1
7 8
1 2 1 3 2 4 2 5 4 6 5 6 6 7 3 7
'''
def DFS(s, V):          # s: 시작정점, V: 정점 개수 (1번부터인 정점의 마지막 정점)
    visited = [0]*(V+1)  # 방문한 정점을 표시
    stack = []           # 스택 생성
    print(s)
    visited[s] = 1     # 시작정점 방문 표시
    v = s               # 현재 정점 : v
    while True:
        for w in adjL[v]:   # v에 인접하고, 방문안한 w가 있으면
            if visited[w] == 0:
                stack.append(v)  # push(v) 현재 정점을 push하고
                v = w              # w에 방문
                print(v)
                visited[w] = 1          # w에 방문표시
                break               # for w, / 남은 갈림길을 두고 v

        else:                   # 남은 인접정점이 없어서 break가 걸리지 않은 경우
            if stack:   # 이전 갈림길을 스택에서 꺼내서... if TOP > -
                v = stack.pop()
            else:           # 되돌아갈 곳이 없으면 / 남은 갈림길이 없으면 탐색 종료
                break       # while true: 에 대한 break


T = int(input())
for tc in range(1, T+1):
    V, E = map(int, input().split())
    adjL = [[] for _ in range(V+1)]
    arr = list(map(int, input().split()))
    for i in range(E):
        v1, v2 = arr[i*2] , arr[i*2+1]
        adjL[v1].append(v2)
        adjL[v2].append(v1)

    DFS(1, V)