[BOJ 17142] 연구소3

2 minute read

문제 출처 : https://www.acmicpc.net/problem/17142

풀이

완전탐색의 전형적인 문제이다.
바이러스의 총 개수와 그 위치를 하나의 item 으로 생각하여, 모든 item 에 대한 경우의 수(M개의 바이러스를 활성화시킬 수 있는 경우의 수)에 대해 고려해주면 된다.

이런 완전탐색 문제에서 combination(또는 permutation) 으로 경우의 수를 빠르게 계산해줄 수도 있으나, 직접 구현하는 경우에 몇 가지 트릭을 적용해 볼 수 있는데, 경우의 수를 조합할 때 이전 index보다 현재 index가 항상 크도록 경우의 수를 조합하게 된다면 시간적인 측면에서 많은 효율 향상을 가지고 올 수 있다.

아래의 어떤 부분이 해당 트릭이 적용되었는지 생각해보자.

C 로만 짜다가 심심해서 python 으로도 짜보았다.
앞으로는 python 으로도 종종 짜보게 될 것 같다.

코드

import sys
input = sys.stdin.readline

import collections

def input2(N, M):
    L = [[int(x) for x in input().split()] for y in range(N)]
    return L

def virus(N, L):
    virus = []
    vcnt = 0
    nvcnt = 0
    for y in range(N):
        for x in range(N):
            if L[y][x] == 2:
                virus.append([y,x])
                vcnt = vcnt+1
            elif L[y][x] == 0:
                nvcnt += 1
    return virus, vcnt, nvcnt

def bfs(act_virus, N, L, nvcnt):
    visited = [[False]*N for _ in range(N)]
    vc = nvcnt
    q = collections.deque(act_virus)
    dy = [0, 1, 0, -1]
    dx = [1, 0, -1, 0]
    lev = 0
    if vc ==0:
        return 0
    for v in act_virus:
        visited[v[0]][v[1]] = True
    while q:
        lev += 1
        for _ in range(len(q)):
            vi = q.popleft()
            #print(vi[0], vi[1])
            for i in range(4):
                y = vi[0] + dy[i]
                x = vi[1] + dx[i]
                if 0 <= y <= N-1 and 0 <= x <= N-1 and not(visited[y][x]) and L[y][x] != 1:
                    visited[y][x] = True
                    if L[y][x] == 0:
                        vc -= 1
                        if vc == 0:
                            return lev

                    q.append([y, x])
    return -1

def dfs(lev, lim, prev, check, act_virus, virus, vcnt, L, N, nvcnt):
    if lev == lim:
        #print(act_virus)
        val = bfs(act_virus, N, L, nvcnt)
        global ans
        #print(val)
        if val != -1 and ans > val:
            ans = val
        return
    for x in range(prev+1, vcnt):
        if check[x] == 0:
            check[x] = 1
            act_virus[lev] = [virus[x][0], virus[x][1]]
            #print(lev, act_virus)
            dfs(lev+1, lim, x, check, act_virus, virus, vcnt, L, N, nvcnt)
            check[x] = 0
    return


def laboratory3(N, M, L, virus, vcnt):
    check = [int(0) for _ in range(vcnt)]
    act_virus = [[int(-1), int(-1)] for _ in range(M)]
    #print(check)
    dfs(0, M, -1, check, act_virus, virus, vcnt, L, N, nvcnt)
    if ans == 500000:
        print(-1)
    else:
        print(ans)

if __name__ == "__main__":
    # execute only if run as a script
    N, M = map(int,input().split())
    L = input2(N, M)
    virus, vcnt, nvcnt = virus(N, L)
    ans = 500000
    laboratory3(N, M, L, virus, vcnt)

개선할 점

python 으로 짜니까 좀 느리다.
그치만 익숙해질 겸 열심히 짜보자.

Leave a comment