백준 15683 감시

gmlwlswldbs·2021년 10월 19일
0

코딩테스트

목록 보기
57/130
import copy
n, m = map(int, input().split())
g = [list(map(int, input().split())) for _ in range(n)]
#cctv 리스트를 만듬 (종류, 좌표)
cctv = []
for i in range(n):
    for j in range(m):
        if 1 <= g[i][j] <= 5:
            cctv.append((g[i][j], i, j))
rotate = [[[0], [1], [2], [3]], #1번 cctv가 가질 수 있는 방향 조합
[[0, 2], [1, 3]], #2번 cctv가 가질 수 있는 방향 조합 rotate[1][0~2]
[[3, 0], [0, 1], [1, 2], [2, 3]],#3번 cctv가 가질 수 있는 방향 조합 rotate[2][0~4]
[[2, 3, 0], [3, 0, 1], [0, 1, 2], [1, 2, 3]],
[[0, 1, 2, 3]]
]
dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]

def change(x, y, d, g):
    # 일단 (x, y)에는 cctv 가 있다.
    # 방향 받아서 그 방향으로 다음 칸이 빈칸이면 -1로 바꿔줌
    nx, ny = x + dx[d], y + dy[d]
    # 다음 확인할 칸이 경계를 넘거나 빈칸이 아니라면 검사 끝남 return 해줌
    if nx < 0 or ny < 0 or nx >= n or ny >= m:
        return g
    elif g[nx][ny] == 6:
        return g
    else:
        # 빈칸이면 -1로 바꿈
        g[nx][ny] = -1
        # 빈칸이면 그 다음도 감시 가능한지 알아본다
        change(nx, ny, d, g)
# 최종적으로 출력할 결과 값
ans = n * m + 1
# cctv의 index를 변경시켜 가며 g를 바꿔나감
def dfs(index, g):
    global ans, n, m
    # 만약 cctv를 전부다 고려했다면 사각지대의 갯수를 센 다음 ans를 업데이트한다
    if index == len(cctv):
        cnt = 0 
        for i in range(n):
            for j in range(m):
                if g[i][j] == 0:
                    cnt += 1
        if cnt < ans:
            ans = cnt
        return ans
    # cctv 의 타입별로 , 90도 회전하며 방향 조합 별로 탐색
    cctvtype, x, y = cctv[index]
    # cctv 타입 별로 가능한 조합 
    for arrows in rotate[cctvtype-1]:
        # 이 전의 그래프를 deepcopy해둠 -> 방향 별로 g가 달라질거니까
        tmp_g = copy.deepcopy(g)
        for arrow in arrows:
            tmp_g = change(x, y, arrow, tmp_g)
        # 방향별로 감시 가능 영역을 다 -1로 표시함
        # 인덱스 늘려서 dfs해서 다음 cctv에 대한 감시 가능 영역을 표시한다
        dfs(index+1, tmp_g)

dfs(0, g)
print(ans)

처음에 이런 코드를 짰었는데
자꾸 TypeError: 'NoneType' object is not subscriptable 가 나와서 뭔가 한참 찾았는데 change 함수에서 return 값이 none이 나오는 경우가 생김
계속 재귀를 들어가고 끝내지 못한다면 return 값을 찾을 수 없는 문제가 생긴다(????)
->재귀함수만(?)의 반환값이 필요 아니면 걍 리턴값을 없애든지 일관성이 필요하다
<<잘 이해 안됨

import copy
n, m = map(int, input().split())
g = [list(map(int, input().split())) for _ in range(n)]
#cctv 리스트를 만듬 (종류, 좌표)
cctv = []
for i in range(n):
    for j in range(m):
        if 1 <= g[i][j] <= 5:
            cctv.append((g[i][j], i, j))
rotate = [[[0], [1], [2], [3]], #1번 cctv가 가질 수 있는 방향 조합
[[0, 2], [1, 3]], #2번 cctv가 가질 수 있는 방향 조합 rotate[1][0~2]
[[3, 0], [0, 1], [1, 2], [2, 3]],#3번 cctv가 가질 수 있는 방향 조합 rotate[2][0~4]
[[2, 3, 0], [3, 0, 1], [0, 1, 2], [1, 2, 3]],
[[0, 1, 2, 3]]
]
dx = [0, 1, 0, -1]
dy = [1, 0, -1, 0]

def change(x, y, d, g):
    # 일단 (x, y)에는 cctv 가 있다.
    # 방향 받아서 그 방향으로 다음 칸이 빈칸이면 -1로 바꿔줌
    nx, ny = x + dx[d], y + dy[d]
    # 다음 확인할 칸이 경계를 넘거나 빈칸이 아니라면 검사 끝남 return 해줌
    if nx < 0 or ny < 0 or nx >= n or ny >= m:
        return
    elif g[nx][ny] == 6:
        return
    else:
        # 빈칸이면 -1로 바꿈
        g[nx][ny] = -1
        # 빈칸이면 그 다음도 감시 가능한지 알아본다
        change(nx, ny, d, g)
# 최종적으로 출력할 결과 값
ans = n * m + 1
# cctv의 index를 변경시켜 가며 g를 바꿔나감
def dfs(index, g):
    global ans, n, m
    # 만약 cctv를 전부다 고려했다면 사각지대의 갯수를 센 다음 ans를 업데이트한다
    if index == len(cctv):
        cnt = 0 
        for i in range(n):
            for j in range(m):
                if g[i][j] == 0:
                    cnt += 1
        if cnt < ans:
            ans = cnt
        return ans
    # cctv 의 타입별로 , 90도 회전하며 방향 조합 별로 탐색
    cctvtype, x, y = cctv[index]
    # cctv 타입 별로 가능한 조합 
    for arrows in rotate[cctvtype-1]:
        # 이 전의 그래프를 deepcopy해둠 -> 방향 별로 g가 달라질거니까
        tmp_g = copy.deepcopy(g)
        for arrow in arrows:
            change(x, y, arrow, tmp_g)
        # 방향별로 감시 가능 영역을 다 -1로 표시함
        # 인덱스 늘려서 dfs해서 다음 cctv에 대한 감시 가능 영역을 표시한다
        dfs(index+1, tmp_g)

dfs(0, g)
print(ans)

return 값을 고쳤다

재귀로 감시 가능한 칸을 바꿔주는 것도 잘 나오는 구현
+) dfs 재귀...

0개의 댓글