[BOJ] Q17142 연구소 3

Question

Language: Python

Difficulty: Gold 4

주어진 그래프에는 비활성화되어 있는 바이러스가 있는데, 이 중에서 m개를 선택해 이를 활성화 시키고, 활성화된 바이러스는 상하좌우로 퍼지게 되는데, 이때 모든 빈칸에 바이러스가 퍼질때까지 걸리는 시간을 체크해야한다.

이 문제는 m개의 바이러스를 선택해서 모든 빈칸에 바이러스를 퍼뜨리는 데 걸리는 최소시간을 구하는 bruteforce 유형의 문제이다.

주의점

비활성되어 있는 바이러스 칸에 퍼지는 경우에 대해서는 시간을 체크해서는 안된다. 이미 해당 칸에는 바이러스가 있기 때문이다.

#이미 바이러스가 있는 칸인 경우 활성화만 시켜주면 되므로 시간이 증가하지 않는다.
if time+1 < visited[next_row][next_col]:
    #비활성화 상태의 바이러스가 있는 칸에 퍼지는 경우 시간은 체크하지 않는다.
    if board[next_row][next_col]!=2:
        max_time=max(max_time,time+1)
    visited[next_row][next_col]=time+1
    queue.append((next_row,next_col,time+1)) 

Solution

from collections import deque
from math import inf

def bfs(activated_viruses):

    visited=[[inf] * n for _ in range(n)]
    dy=[-1,0,1,0]
    dx=[0,1,0,-1]

    queue=deque()
    for row,col in activated_viruses:
        queue.append((row,col,0))
        visited[row][col]=0
    max_time=0
    while queue:
        row,col,time=queue.popleft()
        if visited[row][col] < time:
            continue
        for dir in range(4):
            next_row=row+dy[dir]
            next_col=col+dx[dir]

            if next_row < 0 or next_row >=n or next_col < 0 or next_col >=n:
                continue
            #벽인 경우 퍼지지 못한다.
            if board[next_row][next_col]==1:
                continue
            
            #이미 바이러스가 있는 칸인 경우 활성화만 시켜주면 되므로 시간이 증가하지 않는다.
            if time+1 < visited[next_row][next_col]:
                #비활성화 상태의 바이러스가 있는 칸에 퍼지는 경우 시간은 체크하지 않는다.
                if board[next_row][next_col]!=2:
                    max_time=max(max_time,time+1)
                visited[next_row][next_col]=time+1
                queue.append((next_row,next_col,time+1))
            
                    

    #모든 칸이 바이러스로 덮였는 지 확인한다.
    for row in range(n):
        for col in range(n):
            #빈칸인데, 바이러스가 없는 경우
            if board[row][col]==0 and visited[row][col]==inf:
                    return inf
    return max_time
    
    
def solution(start_index,count,activated_viruses):
    global min_time,visited
    #활성화된 바이러스 m개를 선택완료한 경우
    if count==m:
        min_time=min(min_time,bfs(activated_viruses))
        return

    for i in range(start_index,n_viruses):
        solution(i+1,count+1,activated_viruses+[viruses[i]])
    
def solution(start_index,count,activated_viruses):
    global min_time,visited
    #활성화된 바이러스 m개를 선택완료한 경우
    if count==m:
        min_time=min(min_time,bfs(activated_viruses))
        return

    for i in range(start_index,n_viruses):
        solution(i+1,count+1,activated_viruses+[viruses[i]])

if __name__ == "__main__":
    #predefined globals
    n,m=map(int,input().split())
    viruses=[]
    board=[]
    for i in range(n):
        row=list(map(int,input().split()))
        board.append(row)
        #바이러스 리스트 초기화
        for j in range(n):
            if row[j]==2:
                viruses.append((i,j))

    
    min_time=inf
    n_viruses=len(viruses)
    visited=[]
    solution(0,0,[])
    
    if min_time==inf:
        print(-1)
    else:
        print(min_time)

댓글남기기