[삼성코테] 연구소
Algorithm/DFS BFS

[삼성코테] 연구소

문제

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.

연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다. 

일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.

예를 들어, 아래와 같이 연구소가 생긴 경우를 살펴보자.

이때, 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 곳이다. 아무런 벽을 세우지 않는다면, 바이러스는 모든 빈 칸으로 퍼져나갈 수 있다.

2행 1열, 1행 2열, 4행 6열에 벽을 세운다면 지도의 모양은 아래와 같아지게 된다.

바이러스가 퍼진 뒤의 모습은 아래와 같아진다.

벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다. 위의 지도에서 안전 영역의 크기는 27이다.

연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에 지도의 모양이 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 위치이다. 2의 개수는 2보다 크거나 같고, 10보다 작거나 같은 자연수이다.

빈 칸의 개수는 3개 이상이다.

출력

첫째 줄에 얻을 수 있는 안전 영역의 최대 크기를 출력한다.

 

 

 

 

 

초기접근


벽을 어디다가 세울지 어떻게 계산하지?

 

효율적인 방법을 찾을 수 없을것 같아서 벽을 세우는 모든 경우의 수를 세보았는데

 

가로세로 길이가 최대 8 이므로 최대 64칸.

 

단순하게 64칸에서 3칸을 뽑을 확률을 계산했을때

64 C 3 = 41664.

이정도면 벽 세우는건 모든 경우의 수 다 따져보면 되겠다.

 

 

 

 

아이디어 정립


1. 벽 3개를 세우는 모든 경우의 수 마다,

2. 바이러스가 모두 퍼져나갔을 때의

3. 안전지대 개수를 구하고

4. 안전지대 개수가 가장 클 때의 값을 구한다.

 

바이러스가 퍼져나가는 것은 DFS로 구현한다.

 

 

 

 

 

정답 코드


from itertools import combinations

def dfs(graph, start):
    x = start[0]
    y = start[1]

    graph[x][y] = 2

    # 상 하 좌 우
    dir = [[-1, 0], [1, 0], [0, -1], [0, 1]]

    for d in dir:
        nowx = x+d[0]
        nowy = y+d[1]

        if nowx < 0 or nowx >= n or nowy < 0 or nowy >= m:
            continue

        if graph[nowx][nowy] == 0:
            dfs(graph, [nowx, nowy])


def initLab(sourceLab):
    reLab = [[0]*len(sourceLab[0]) for i in range(len(sourceLab))]
    for i in range(len(sourceLab)):
        for j in range(len(sourceLab[0])):
            reLab[i][j] = sourceLab[i][j]
    return reLab


n, m = map(int, input().split())

lab = []
zero = []
start = []
for i in range(n):
    lab.append(list(map(int, input().split())))
    for j in range(m):
        if lab[i][j] == 0:
            zero.append([i, j])
        if lab[i][j] == 2:
           start.append([i, j])

pickwall = list(combinations(zero, 3))

result = []
# 벽 세개 세우는 경우 다 해보기
for i in range(len(pickwall)):

    tempLab = initLab(lab)
    for p in pickwall[i]:
        x = p[0]
        y = p[1]

        tempLab[x][y] = 1

    # 모든 바이러스로부터 시작
    for st in start:
        dfs(tempLab, st)

    # 안전지대 개수 세기
    count = 0
    for j in range(n):
        for k in range(m):
            if tempLab[j][k] == 0:
                count += 1
    result.append(count)

print(max(result))

 

 

 

 

 

헤맸던 점


처음에는 tempLab = initLab(lab) 처럼 새로 리스트를 초기화 시켜주는 것이 아닌

 

tempLab = lab * [len(pickwall)] 로 미리 리스트를 만들어 놓고 차례로 쓰려고 했었다.

 

그런데 tempLab = lab * [len(pickwall)] 이렇게 코드를 작성하고 실행했을때

tempLab[0]을 수정해도 tempLab[1], tempLab[2] .. 같이 나머지의 리스트원소도 값이 바뀌었다.

 

리스트가 모든 원소에 다 "참조"로 들어간 것이다.

 

파이썬의 유일한 단점이 list() = list()를 해줬을때 항상 참조가 된다는 점이다.

다른 문제에서는 여기서 헤매지 말고 신속히 리스트에 값을 직접 넣는 함수를 따로 만들자.

'Algorithm > DFS BFS' 카테고리의 다른 글

[삼성 역량테스트] 인구이동  (0) 2021.01.27
[삼성 코테] 연산자 끼워넣기  (0) 2021.01.26
[백준] 감시 피하기  (0) 2021.01.26
[카카오코테] 괄호변환  (0) 2021.01.25
[백준] 경쟁적 전염  (2) 2021.01.22