-
[Python] 백준 15683번 문제 풀이 - 감시코딩테스트 2025. 8. 18. 18:32
문제 링크
https://www.acmicpc.net/problem/15683
문제 이해
이 문제는 지도와 CCTV와 벽이 주어졌을 때 CCTV가 감시하지 못하는 영역을 최소로 만드는 문제입니다.
CCTV는 5종류가 있습니다.
- 1번 CCTV : 상 하 좌 우 한방향씩만 탐색 가능
- 2번 CCTV : 상하 좌우 두방향씩 탐색 가능
- 3번 CCTV : 상우, 상좌, 하우, 하좌 탐색 가능
- 4번 CCTV : 상하우, 상하좌, 좌우상, 좌우하 탐색 가능
- 5번 CCTV : 상하좌우 탐색 가능
다음 CCTV들이 각각 어떤 방향을 감시할 때 감시하지 못하는 영역이 가장 작아지는지 출력하면 됩니다.
CCTV는 벽 너머는 감시할 수 없고 벽이 없다면 끝까지 감시 가능합니다. 끝까지 가는 중에 CCTV가 있어도 끝까지 감시할 수 있습니다.
아이디어
이 문제를 해결하는 아이디어는 다음과 같습니다. CCTV 개수를 8로 가정하고 하겠습니다.
- 우선 CCTV 5개의 방향을 저장해둔다.
- 1번~8번까지 한 방향으로 dfs로 탐색하며 마지막 CCTV까지 탐색한다.
- 8번 CCTV까지 탐색이 끝났다면 현재 감시하지 못하는 영역이 몇개나 있는지 찾고 최소값을 최신화한다.
- 그리고 8개의 CCTV의 모든 방향의 조합을 다 해보고 최소값을 출력한다.
시간복잡도
이 아이디어의 시간복잡도는 CCTV가 최대 8개이고 각 CCTV의 방향은 1,3,4번의 경우 최대 4개가 될 수 있으니
4^8이 됩니다. 이것은 2^16으로 바꿀 수 있습니다.
그리고 내부 함수에서 CCTV가 감시할 수 있는 범위를 측정할 때는 최대 8*8에서 수행하기 때문에 한 탐색마다 2^6의 시간이 걸립니다. 그러면 총 시간복잡도는 2^22으로 400만정도가 나와서 가능합니다.
코드 구현
이 아이디어를 코드로 구현하면 다음과 같습니다.
import copy n, m = map(int, input().split()) cctv = [] board = [] mode = [ [], [[0], [1], [2], [3]], # 1번 cctv [[0,2], [1,3]], # 2번 cctv [[0,1], [1,2], [2,3], [0,3]], # 3번 cctv [[0,1,2], [0,1,3], [1,2,3], [0,2,3]], # 4번 cctv [[0,1,2,3]] # 5번 cctv ] # 북 동 남 서 방향 dx = [-1, 0, 1, 0] dy = [0, 1, 0, -1] # 보드 넣기 for i in range(n): data = list(map(int, input().split())) board.append(data) # 넣는 중 CCTV 발견되면 CCTV 배열에 추가 for j in range(m): if data[j] in [1,2,3,4,5]: cctv.append([data[j], i, j]) # cctv가 감지하는 범위 확인하는 함수 def fill(board, mode, x, y): # 3번 cctv면 mode : [[0,1], [1,2], [2,3], [0,3]] for i in mode: nx = x ny = y while True: # 이동방향으로 쭉 이동 nx += dx[i] ny += dy[i] # 범위 나가면 끝 if nx < 0 or ny < 0 or nx >= n or ny >= m: break # 벽이면 끝 if board[nx][ny] == 6: break # 만약에 탐지 가능하면 -1로 탐지했다는 표시 elif board[nx][ny] == 0: board[nx][ny] = -1 # CCTV가 탐지할 수 있는 모든 경우의 수 구하는 함수 def dfs(depth, board): global min_value # 전체 CCTV 다 탐색했을 경우 if depth == len(cctv): count = 0 # 탐지 안된 구역 세고 for i in range(n): count += board[i].count(0) # 가장 적게 탐지가 된 구역 최신화 min_value = min(min_value, count) return temp = copy.deepcopy(board) # 이전 CCTV 탐색한 맵 가져오기 cctv_num, x, y = cctv[depth] # 현재 CCTV 종류와 좌표 가져오기 for i in mode[cctv_num]: fill(temp, i, x, y) # 현재 CCTV 감지 범위 확인 dfs(depth+1, temp) # 다음 CCTV에 현재 감지한 범위의 배열 넣어주기 temp = copy.deepcopy(board) # 위의 함수에서 길이가 8로 다 돌았으면 7번째의 지도로 바꾼 후에 8번 CCTV의 다음 방향 탐색 min_value = 64 dfs(0, board) print(min_value)
느낀 점
아이디어는 떠올렸는데 방향을 어떻게 설정해야할지 감이 안왔고, 어떻게 모든 CCTV의 방향을 탐색 할 수 있을지에 대한 코드 구현 능력이 부족했습니다.
그래서 다음 블로그를 참고하여 코드를 참고하여 이해하는 방식으로 문제를 풀었습니다.
https://yeon-code.tistory.com/76
[python] BOJ 백준 15683: 감시
1. 문제 스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV
yeon-code.tistory.com
재귀함수와 백트래킹을 다른 사람의 코드를 보고 겨우 이해는 하겠지만 직접 짤 때는 어떻게 짜야할지 아직 감이 안와서 문제를 더 풀어보며 아이디어를 떠올릴 수 있게 많이 풀어봐야 할 듯합니다.
'코딩테스트' 카테고리의 다른 글
[Python] 백준 15685번 문제 풀이 - 드래곤 커브 (0) 2025.08.20 [Python] 백준 17144번 문제 풀이 - 미세먼지 안녕! (0) 2025.08.19 [Python] 백준 17837번 문제 풀이 - 새로운 게임 2 (3) 2025.08.15 [Python] 백준 14890번 문제 풀이 - 경사로 (4) 2025.08.14 [Python] 백준 2563번 문제 풀이 - 색종이 (4) 2025.08.14