ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DFS - 음료수 얼려먹기
    알고리즘 2022. 9. 26. 21:56

    DFS (Depth First Search)

    DFS, 깊이 우선 탐색이란 그래프에서 가장 깊이 있는 노드부터 탐색하는 알고리즘이다.

    일반적으로 stack 자료구조와 재귀함수를 통해 구현할 수 있다. 

     

    음료수 얼려 먹기

    이코테에서 DFS 대표 문제로 '음료수 얼려 먹기' 문제가 있다. 

    N X M 크기의 얼음 틀이 있을때, 음료를 담을 수 있는 칸은 0으로, 막힌 칸은 1로 표시가 되어있다.

    그래서 틀의 모양에 따라 몇 덩이의 얼음 덩어리가 나오는지 세는 문제이다. 

     

    [input]
    1. n(세로길이) 과 m(가로길이)가 띄어쓰기로 입력 된다.
    2. n X m 의 2차원 리스트가 한줄씩 0과 1로 입력된다.
    ex)
    001
    010
    101
    
    [output]
    구할 수 있는 얼음 덩어리의 개수

    이 문제가 왜 DFS 문제일까? 🤔

    그래프에서 0은 서로 이어져있어서 방문할 수 있는 노드, 1은 방문할 수 없는 노드라고 생각하고

    '하나의 노드에서 이어져있는 모든 노드를 방문한다' 고 생각하면 되기 때문에 DFS로 풀 수 있는 것이다.

     

    답안 코드

    n, m = map(int, input().split())
    
    graph = []
    for i in range(n):
    	graph.append(list(map(int, input())))
    
    def dfs(x, y)
    	# x와 y가 2차원 리스트의 범위 밖이라면 return False
    	if not 0 <= x < n or not 0 <= y < m:
        	print(graph)
        	return False
        
        # 해당 노드가 0이라면 1로 방문표시하고, 해당 노드의 상하좌우 모두 재귀적으로 확인
        if graph[x][y] == 0:
        	graph[x][y] = 1
            print(graph)
            dfs(x-1, y)
            dfs(x, y-1)
            dfs(x+1, y)
            dfs(x, y+1)
            return True
            
        # 해당 노드가 1이라서 방문할 수 없다면 return False
        print(graph)
        return False
        
        answer = 0
        
        for i in range(n):
        	for j in range(m):
           		print(f'i: {i}, j: {j}')
        		print(dfs(i, j))
            	# 그래프의 (0, 0)부터 (n, m)까지 dfs 함수 실행하고 값이 True인 경우만 카운트
            	if dfs(i, j) == True:
                	answer += 1

    책에서 답안 코드를 보고도 이해가 잘 되지 않는 부분이 있었다. 

     

    • 시작 노드의 상하좌우 노드들을 확인하기 위해 재귀적으로 dfs 함수를 호출할때 return 되는 값은 영향을 안미치는가?

    ➡️ 유튜브에서 해설을 찾아보니까 답을 얻을 수 있었다. 해당 부분에서의 return 값은 따로 사용하지 않고, 단순히 시작점에서 연결된 0을 1로 바꿔주기만 한다.


    • 재귀적으로 dfs 함수를 호출하는 부분에서 그래프가 어떻게 바뀌는가?

    ➡️ 이 부분을 확인하기 위해 return이 되는 경우가 세 가지가 있고 각각 graph를 프린트하여 확인해 보았다.

    아래 사진은 graph가 위의 예시처럼 입력 되었을 때의 출력문이다. [[0,0,1], [0,1,0], [1,0,1]]

    for 문에서 그래프의 (0,0)부터 (n,m)까지 노드들에 대해 dfs 함수를 실행 시킬때, 노드의 위치인 i와 j값과 return 값을 함께 출력했다.

    처음 시작인 (0,0)이 0이었기 때문에 1로 바뀐것이 그래프 출력문 중 첫 줄의 [[1,0,1], [0,1,0], [1,0,1]] 이다.

     

    그러고 나서 (0,0) 을 기준으로 상하좌우를 확인하기 위해 dfs 함수가 네 번 더 호출되는데, (0,0)의 아래인 (x+1, y) 즉, (1,0)을 확인했을때 그 값이 0이므로 해당 위치를 1로 바꿔서 그래프의 모습이 한번 더 바뀐다.

    그게 그래프 출력문 중 넷째 줄인 [[1,0,1], [1,1,0], [1,0,1]] 이다. 

     

    이 시점부터는 (1, 0)을 기준으로 재귀함수들을 모두 호출한 뒤 다시 원래 기준이었던 (0,0)으로 돌아와서 실행하지 못한 나머지 재귀함수를 마저 호출한다. 


    • for 문에서 dfs를 실행한 결과가 True 인 경우만 count하는게 무슨 의미인가?

    ➡️ (0,0)부터 (n,m)까지 모두 dfs를 실행하고, 그 중 값이 0인 위치에서만 유일하게 재귀함수들 호출과 True가 return 된다. 

    즉, 일단 0을 감지한 순간 그 0과 연결된 모든 0들을 다 확인한 다음에 True를 반환하기 때문에 0을 1로 바꾸는 코드가 실행될 때만 카운트를 하면 덩어리의 개수를 셀 수 있는 것이다.

     

     

     

     

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

    Greedy - 큰 수 만들기  (0) 2022.10.17
    DFS, BFS - 타겟넘버  (0) 2022.09.29
    파이썬 Deque와 List의 pop( )  (2) 2022.09.15
    유클리드 호제법 - 최대공약수, 최소공배수  (0) 2022.09.06
    약수의 합  (0) 2022.09.05
Designed by Tistory.