반응형
snowman95
코딩수련장
snowman95
전체 방문자
오늘
어제
  • 분류 전체보기 (229)
    • 앱테크 (3)
    • 옵시디언 (5)
    • 드라마, 영화 (1)
    • 개발자 이야기 (23)
    • 프로젝트 (10)
      • 프로젝트 방법론 (7)
      • 프로젝트 기록 (2)
      • Github (1)
    • 개발 지식 (0)
      • 디자인 패턴 (0)
    • 프론트엔드 개발 (5)
      • 테크트리 (2)
      • React.js (19)
      • ReactNative (2)
      • Next.js (6)
      • GraphQL (6)
      • 패키지 매니저 (2)
      • 라이브러리 (3)
      • 상태관리 라이브러리 (4)
      • Web 지식 (3)
      • HTML CSS (26)
      • Javascript (16)
      • 도구 (Tool) (3)
      • 성능 최적화 (1)
      • 디자인시스템 (0)
    • Python (53)
      • 모음집 (1)
      • 문법 (12)
      • 라이브러리 (15)
      • 알고리즘 (10)
      • 백준 문제풀이 (9)
      • 코딩테스트 (2)
      • 도구 (Tool) (3)
    • C++ (20)
      • 알고리즘 (6)
      • 삼성SW기출 (6)
      • 삼성 A형 (6)
    • 데이터사이언스 (1)
    • 인프라 (9)
      • 하드웨어 지식 (4)
      • Ansible (2)
      • Database (2)
      • 쉘스크립트 (1)
    • 주식 (0)
    • 취업 준비 (4)
      • 취업 이야기 (0)

블로그 메뉴

  • 홈
  • 태그

공지사항

인기 글

태그

  • 공간복잡도
  • 티스토리챌린지
  • 언어
  • A형
  • 오블완
  • 삼성SDS
  • Next.js #graphql #tailwind.css
  • C++
  • 백준
  • 기계식키보드 #nuphy
  • nextjs
  • 알고리즘
  • 전공 요약 #운영체제
  • 전공 요약 #데이터베이스
  • 전공요약
  • GraphQL
  • 삼성SW역량테스트
  • 전공 요약 #네트워크
  • 면접
  • 나의 해방일지

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
snowman95
Python/알고리즘

파이썬(python) 알고리즘 - DFS, BFS

파이썬(python) 알고리즘 - DFS, BFS
Python/알고리즘

파이썬(python) 알고리즘 - DFS, BFS

2021. 4. 22. 21:25
728x90
반응형

 


DFS (깊이 우선 탐색)


깊이를 우선으로 탐색하는 알고리즘

 

  1. 시작 노드에서 방문하지 않은 인접 노드를 큐에 삽입 (방문 했음을 표시)
  2. 더 이상 방문할 수 없는 경우 탐색 중단하고 이전 상태로 되돌아옴

특징

  1. 스택 or 재귀함수 사용
  2. 한 방향으로 최대한 깊게 접근해본다
  3. (경고) 파이썬 최대 재귀 횟수는 1000번까지 가능하다.
    재귀를 많이 호출하는 문제는 제한횟수에 걸려서 런타임 에러가 발생할 수도 있다.
    sys.setrecursionlimit(제한횟수) 로 제한을 늘릴 수 있다.
    import sys
    sys.setrecursionlimit(제한횟수)

기본 형태

def dfs(arr, cur, visited):
    visited[cur] = True
    for i in arr[cur]:
        if not visited[i]:
            dfs(arr, cur, visited)

BFS (너비 우선 탐색)


너비를 우선으로 탐색하는 알고리즘

  1. 시작 노드에서 방문하지 않은 인접 노드를 큐에 삽입 (방문 했음을 표시)
  2. 큐가 빌 때까지 큐에서 하나씩 꺼내서 방문하지 않은 인접 노드를 큐에 삽입 (방문 했음을 표시)

특징

  1. 큐 사용
  2. 매 순간이 최적의 경우임을 보장한다.
  3. (경고) 방문 Check를 반드시 큐에 '넣기 전'에 해주어야 한다.
    큐에서 빼낸 후 방문check를 해주어도 로직상으로는 문제 없지만
    불필요한 방문이 큐에 쌓이기 때문에 중복으로 방문되는 경우가 많이 생겨서 메모리 초과가 발생한다.

기본 형태

from collections import deque

def bfs(arr, start, visitet):
    queue = deque([start])
    visited[start] = True
    while queue:
        cur = queue.popleft()
        for i in arr[cur]:
            if not visited[i]:
                queue.append(i)
                visited[i] = True

 

 

파이썬 (python) 라이브러리 - collections.deque

collections.deque 파이썬에서 queue를 이용할때 사용한다. list를 이용하면 add 연산에 O(n) 만큼의 시간이 들기 때문에 deque를 사용해야함. 데이터가 오른쪽으로 추가되고 왼쪽으로 나가는 형태 q = collect

11001.tistory.com

 

DFS와 BFS 단계

BFS의 특징은 각 정점을 최단경로로 방문한다는 것입니다. 이 점을 활용해 최단거리를 구해 봅시다.

www.acmicpc.net

 


BFS vs DFS

 

(공식) 가중치가 없는 최단 경로 : BFS

  • DFS : 특정 칸에 처음 도달했을 때까지의 경로 길이가 다른 경로를 통해 도달한 길이보다 짧다는 보장못함.
  • BFS : 특정 칸에 처음 도달했을 때까지의 경로 길이가 항상 최적임을 보장

 

(권장) DFS는 스텍 터질 위험이 커서 BFS 사용합시다.

(권장) 최대 길이를 구하는 문제는 BFS 가 유리하다는 의견이 많음


그래프 탐색 문제 유형을 파해쳐보자.

 

1. (인접리스트) 방문(전파) 가능한 노드 개수 구하라

  • a→b, b→c 이러한 인접리스트 형태의 입력
    a→b, b→c 이므로 a→b→c 가된다. 즉, a에서는 b와 c 방문가능
  • 현재 위치에서 인접(갈 수 있는) 노드 中 한 번도 방문한 적 없다면 방문한다.
  • 방문할 때마다 cnt 1증가시켜서 방문 가능한 위치 개수 구한다.
  • 방문한 위치는 다시는 방문 못하도록 방문 여부 True로 변경
cnt = 0
def dfs(cur, arr, visited):
    global cnt
    visited[cur] = True
    for i in arr[cur]:
        if not visited[i]:
            cnt +=1
            dfs(i, arr, visited)
 

2606번: 바이러스

첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어

www.acmicpc.net

 

2. (인접 행렬) 목적지 까지 도달할 때의 최단 거리 구하기

  • 2차원 바둑판 형태의 입력
  • 상하좌우 4방향으로 말을 이동하여 최단 경로로 목적지 까지 도착하는 문제
  • dx, dy라는 move offset 변수를 두어서, 상하좌우 이동을 for문 하나로 구현한다.
dx = [1,-1,0,0]
dy = [0,0,1,-1]
def bfs(x,y, board, visited):
    # 시작점도 이동 카운트로 치면 큐에 1 넣고, 아니면 0으로
    q = collections.deque([(x,y,1)])
    visited[x][y] = True
    while q:
        cur = q.popleft()
        # 목적지 도달한 경우 (BFS는 현재가 항상 최적 경로임을 보장)
        if cur[0]==n-1 and cur[1] ==m-1 :
            print(cur[2])
            return
        for i in range(4):
            xx = dx[i] + cur[0]
            yy = dy[i] + cur[1]
            if 0<=xx<n and 0<=yy<m and not visited[xx][yy] and board[xx][yy] == '1':
                visited[xx][yy] = True
                q.append((xx,yy,cur[2]+1))
 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

3. (인접 행렬) 서로 인접하지 않은 (독립된) 지역의 개수 구하기

  • 2차원 바둑판 형태의 입력
  • 상하좌우대각선, 총 8방향으로 1칸이라도 붙어있으면 인접하다고 가정
  • (0,0)부터 (n,m)까지 이중 for문을 돌면서 방문하지 않은 곳을 시작점으로 잡고 방문가능한 곳을 모두 방문한다. 
  • 즉, BFS/DFS를 수행하면 하나의 독립된 지역을 탐색하는 것이다. 지역+1을 해준다.
dx = (1,-1,0,0,-1,-1,1,1)
dy = (0,0,1,-1,-1,1,-1,1)

def dfs(x,y):
    global visited, xx, yy
    visited[x][y] = True
    for i in range(8):
        xx = dx[i]+x
        yy = dy[i]+y
        # 이 예시에서는 board가 1인 지역을 방문 가능하다고 가정
        if 0<=xx<n and 0<=yy<m and board[xx][yy] == 1 and not visited[xx][yy]:
            dfs(xx,yy)

visited = [[False] * m for _ in range(n)]
cnt = 0   # 독립된 지역의 개수
for i in range(n):
    for j in range(m):
        if board[i][j] == 1 and not visited[i][j] :
            dfs(i,j) # 하나의 독립된 지역을 탐색
            cnt+=1
 

4963번: 섬의 개수

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 지도의 너비 w와 높이 h가 주어진다. w와 h는 50보다 작거나 같은 양의 정수이다. 둘째 줄부터 h개 줄에는 지도

www.acmicpc.net

 

 

4. (인접 행렬) 정상 노드 감염 시키기

  • 2차원 바둑판 형태의 입력
  • 상하좌우, 총 4방향으로 1칸이라도 붙어있으면 인접하다고 가정
  • 정상 노드와 감염 노드가 존재함
  • 감염된 노드는 매초마다 인접한 방향으로 퍼져나간다. 정상 노드를 만나면 감염 노드로 변이시킨다.
  • 더 이상 감염시킬 노드 없을 때 까지 진행
  • 감염된 노드들을 모두 큐에 넣고 시작. 전파 중에 새롭게 감염된 노드만 큐에 넣음
visited = [[False]*m for _ in range(n)]
q = collections.deque()

for i in range(n):
        for j in range(m):
        # 이 예시에서는 board가 1인 노드가 감염 노드로 간주 = 모두 큐에 넣는다.
            if board[i][j] == 1:
                q.append((i,j,0))
                visited[i][j] = True
while q:
        cur = q.popleft()
        for i in range(4):
            xx = dx[i]+cur[0]
            yy = dy[i]+cur[1]
            max_day = max(max_day, cur[2])
            if xx >=0 and yy>=0 and xx<n and yy<m:
                next_day = cur[2]+1
                # 이 예시에서는 board가 0인 노드를 새롭게 감염시킨다고 가정
                if not visited[xx][yy] and board[xx][yy] == 0:
                    normal_tomato_cnt -= 1
                    visited[xx][yy] = next_day
                    q.append((xx,yy,next_day))
 

파이썬(python) 백준 7576 : 토마토

7576번: 토마토 첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에

11001.tistory.com

 

 

5. (인접 행렬) 동일 위치에 재 방문이 가능한 경우

  • 2차원 바둑판 형태의 입력
  • 상하좌우, 총 4방향으로 1칸이라도 붙어있으면 인접하다고 가정
  • 문제의 특수한 조건 때문에 같은 위치에 재방문이 가능함.
  • 따라서 방문 검사 배열에 True/False 아닌 다른 정보를 저장해야 함.

예제 1) 방문여부 대신에 최단 거리를 기록 & 방문 기록 배열을 2개의 Case로 나누어 기록

  • 조건 : 목적지 까지의 최단 거리 구하는데 갈 수 없는 벽을 1번 뚫고 지나갈 수 있다.
  • 문제점 : 같은 위치에 도달하더라도 1.벽은 부순 경우와 2.벽을 부수지 않은 경우, 총 2가지 존재
  • 해결책 : 
    1. 벽 부순 경우와 2. 벽 안 부순 경우의 현재 위치까지의 최단거리를 각각 다른 방문 검사 배열에 저장
    - 배열 1 : 벽은 부순 경우 현재 위치까지의 최단거리 저장
    - 배열 2 : 벽을 부수지 않은 경우 현재 위치까지의 최단거리 저장

    그리고 벽을 부쉈는지 여부
    (True/False)를 큐에 같이 저장해서 현재 상태를 확인 할 수 있게 한다.
    벽을 부쉈다면 1번 배열, 안 부쉈다면 2번 배열의 정보를 사용한다.
 

파이썬(python) 백준 2206 : 벽 부수고 이동하기

2206번: 벽 부수고 이동하기 N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하

11001.tistory.com

 

예제 2) 방문 여부 대신에 경로 자체를 기록

  • 조건 : 최대한 많은 칸을 지나야하는데 각 칸에는 대문자 알파벳있다. 각 알파벳을 단 1번씩만 지나갈 수 있다.
  • 문제점 : 똑같은 위치에 여러가지 경로를 거쳐서 올 수 있음 (알파벳을 다르게 지나서 도착)
  • 해결법 : 경로 자체를 큐 또는 리스트에 저장한다.
    똑같은 경로로 도달했으면 무시, 다른 경로로 도달했으면 큐 또는 리스트에 넣고 계속 진행
 

파이썬(python) 백준 1987 : 알파벳

1987번: 알파벳 세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네

11001.tistory.com


백트래킹


특징

백트래킹은 DFS 알고리즘의 하위 분류이다.

DFS(재귀)를 수행하여 타고타고 깊게 들어가다가 특정 조건을 만나면 탐색 중단하고 되돌아간다.

그 과정에서 원하는 해를 찾는 알고리즘이다.

 

 

백트래킹 단계

조금 더 복잡한 백트래킹 문제 1

www.acmicpc.net

 

문제 풀이

 

 

반응형
저작자표시 동일조건 (새창열림)

'Python > 알고리즘' 카테고리의 다른 글

파이썬(python) 알고리즘 - 최단 경로 (다익스트라)  (0) 2021.05.09
파이썬(python) 알고리즘 - 동적 계획법 푸는 방법  (0) 2021.04.28
파이썬 (python) 알고리즘 - 그리디 알고리즘  (0) 2021.04.22
파이썬(python) 알고리즘 - 소수 찾기  (0) 2021.04.18
파이썬(python) 알고리즘 - 팩토리얼  (0) 2021.04.18
  • DFS (깊이 우선 탐색)
  • BFS (너비 우선 탐색)
  • BFS vs DFS
  • 그래프 탐색 문제 유형을 파해쳐보자.
  • 1. (인접리스트) 방문(전파) 가능한 노드 개수 구하라
  •  
  • 2. (인접 행렬) 목적지 까지 도달할 때의 최단 거리 구하기
  •  
  • 3. (인접 행렬) 서로 인접하지 않은 (독립된) 지역의 개수 구하기
  • 4. (인접 행렬) 정상 노드 감염 시키기
  • 5. (인접 행렬) 동일 위치에 재 방문이 가능한 경우
  • 백트래킹
'Python/알고리즘' 카테고리의 다른 글
  • 파이썬(python) 알고리즘 - 최단 경로 (다익스트라)
  • 파이썬(python) 알고리즘 - 동적 계획법 푸는 방법
  • 파이썬 (python) 알고리즘 - 그리디 알고리즘
  • 파이썬(python) 알고리즘 - 소수 찾기
snowman95
snowman95
(17~19) Unity/Unreal Engine 게임 프로그래머 (20~21) System Administrator ___________ (22~) React 웹 프론트앤드 개발자 __________ 깃헙 : https://github.com/snowman95

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.