[BOJ] Q3109 빵집

Question

Language: Python

Difficulty: Gold 2

해당 문제는 파이프라인을 설치할 때 최대한 윗쪽 좌표를 우선적으로 탐색하여 파이프라인 설치 가능 여부를 조사해서 설치를 진행한다.

처음에는 bfs을 활용해서 첫 열에서 마지막 열 까지 도달가능한 경로가 있는지 파악하려고 했다.

Failed Solution

import sys
from collections import deque
def print_board(board):
    for row in board:
        print(*row)

def solution():
    visited=[[False] * n_cols for _ in range(n_rows)]

    dy=[-1,0,1]
    dx=[1,1,1]
    pipeline_count=0
    for start_row in range(n_rows):
        queue=deque([(start_row,0,[])])
        pipeline_path=[]
        while queue:
            row,col,path=queue.popleft()
            #끝점에 도달한 경우
            if col == (n_cols-1):
                pipeline_path=path
                break

            for dir in range(3):
                next_row=row + dy[dir]
                next_col=col + dx[dir]

                #격자를 벗어나는 경우
                if next_row < 0 or next_row >=n_rows or next_col < 0 or next_col >=n_cols:
                    continue
                
                #벽인 경우
                if board[next_row][next_col]== "x":
                    continue
                    
                #이미 파이프 라인이 설치되어 있는 경우
                if visited[next_row][next_col]:
                    continue
                queue.append((next_row,next_col,path+[dir]))
        
        #끝열에 도달한 경우 --> 파이프라인을 설치할 수 있는 경우
        if pipeline_path != []:
            current_row,current_col=start_row,0
            visited[current_row][current_col]=True

            for dir in pipeline_path:
                current_row += dy[dir]
                current_col += dx[dir]
                visited[current_row][current_col]=True
            
            pipeline_count+=1
    
    print(pipeline_count)
if __name__ == "__main__":
    n_rows,n_cols=map(int,input().split())
    board=[list(input()) for _ in range(n_rows)]
    
    solution()

하지만 위와 같이 하면 여러 개의 path을 동시에 저장해야되므로 메모리 초과가 발생하게 된다.

따라서, 경로를 메모리에 저장하지 않고 우선적으로 탐색을 통해 도달 가능한 경로가 있는지 파악하기 위해 dfs을 활용한다.

핵심 로직

아래의 dfs 경우에 대한 조건 검사를 수행하여 참일떄(경로가 탐색된 경우) return을 수행하여 더 이상 진행하지 않도록 하는 것이 중요하다.

if find_path(next_row,next_col,path+[(next_row,next_col)]):
    return True

Solution

def find_path(row,col,path):
    global visited,pipeline_count
    if col == (n_cols-1):
        pipeline_count+=1
        return True
        
    for dir in range(3):
        next_row=row + dy[dir]
        next_col=col + dx[dir]

        #격자를 벗어나는 경우
        if next_row < 0 or next_row >=n_rows or next_col < 0 or next_col >=n_cols:
            continue
        
        #벽인 경우
        if board[next_row][next_col]== "x":
            continue
            
        #이미 파이프 라인이 설치되어 있는 경우
        if visited[next_row][next_col]:
            continue
        visited[next_row][next_col]=True
        if find_path(next_row,next_col,path+[(next_row,next_col)]):
            return True
    return False

def solution():
    for start_row in range(n_rows):
        find_path(start_row,0,[(start_row,0)])
    
    print(pipeline_count)
if __name__ == "__main__":
    n_rows,n_cols=map(int,input().split())
    board=[list(input()) for _ in range(n_rows)]
    visited=[[False] * n_cols for _ in range(n_rows)]
    dy=[-1,0,1]
    dx=[1,1,1]
    pipeline_count=0
    solution()

댓글남기기