ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 15683] 감시 (Python)
    Algorithm & Problem Solving/브루트포스(Brute Force) 2021. 2. 14. 19:37

    www.acmicpc.net/problem/15683

     

    15683번: 감시

    스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

    www.acmicpc.net

     

    문제풀이

    N, M, board : 입력값

    cctv, cctv_n : CCTV 좌표 리스트, CCTV 개수

    ans : 최소 사각지대 개수

    check : 방문 여부 확인

     

    재귀를 이용해 모든 CCTV를 4방향 돌리면서 감시 가능 영역을 만들어보는 브루트포스 방식으로 해결할 수 있다.

     

    1. CCTV 좌표 및 개수 세주기

     

    2. 재귀를 이용해 모든 CCTV의 감시 영역 탐색하기

    - CCTV 종류에 따라서 방향 다르게 감시 영역 확인

    - 1번 CCTV : 현재 방향

    - 2번 CCTV : 현재 방향 + 반대 방향

    - 3 CCTV : 현재 방향 + 왼쪽 90도 방향

    - 4 CCTV : 현재 방향 + 반대 방향 + 왼쪽 90도 방향

    - 5 CCTV : 4방향

    - 방향 설정 후 해당 방향으로 벽이나 리스트 끝에 도달할 때 까지 방문

    - 벽이나 리스트 끝에 도달하면 다음 CCTV 재귀호출

    - 모든 CCTV 탐색 후 사각지대 개수 확인

     

    코드

    import sys
    from collections import deque
    
    dx = [0, 1, 0, -1]
    dy = [1, 0, -1, 0]
    
    def solution(cnt):
        global check, ans
        if cnt == cctv_n: # 모든 CCTV 탐색했다면 사각지대 개수 세주기
            tmp = 0
            for i in range(N):
                for j in range(M):
                    if not board[i][j] and not check[i][j]:
                        tmp += 1
            return tmp
        x, y = cctv[cnt][0], cctv[cnt][1]
        for k in range(4): # CCTV 의 4방향 확인
            new_dir = []
            if board[x][y] == 1: # 1번 CCTV : 현재 방향
                new_dir.append(k)
            elif board[x][y] == 2: # 2번 CCTV : 현재 방향 + 반대 방향
                new_dir.append(k)
                new_dir.append((k + 2) % 4)
            elif board[x][y] == 3: # 3번 CCTV : 현재 방향 + 왼쪽 90도 방향
                new_dir.append(k)
                new_dir.append((k - 1) % 4)
            elif board[x][y] == 4: # 4번 CCTV : 현재 방향 + 반대 방향 + 왼쪽 90도 방향
                new_dir.append(k)
                new_dir.append((k - 1) % 4)
                new_dir.append((k + 2) % 4)
            elif board[x][y] == 5: # 5번 CCTV : 4방향
                new_dir.append(k)
                new_dir.append((k - 1) % 4)
                new_dir.append((k + 1) % 4)
                new_dir.append((k + 2) % 4)
            q = deque()
            for d in new_dir: # CCTV 방향 개수 만큼 이동
                nx, ny = x + dx[d], y + dy[d]
                while 0 <= nx < N and 0 <= ny < M: # 특정 방향으로 끝까지 이동
                    if not check[nx][ny] and board[nx][ny] != 6: # 방문하지 않았으며 벽이 아니면
                        check[nx][ny] = True # 방문
                        q.append((nx, ny))
                    elif board[nx][ny] == 6: break # 벽이면 중단
                    nx += dx[d]
                    ny += dy[d]
            # 다음 CCTV 호출
            ans = min(ans, solution(cnt + 1))
            # 방문했던 곳 되돌려주기
            while q:
                qx, qy = q.popleft()
                if not board[qx][qy]:
                    check[qx][qy] = False
            # 5번 CCTV 는 회전할 필요 없으므로 바로 break
            if board[x][y] == 5: break
        return ans
    
    if __name__ == '__main__':
        N, M = map(int,sys.stdin.readline().split())
        board = [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
        cctv = []
        cctv_n = 0 # 전체 CCTV 개수
        ans = 0 # 사각지대
        check = [[False] * M for _ in range(N)] # 방문 여부 확인
        for i in range(N):
            for j in range(M):
                if board[i][j] and board[i][j] != 6:
                    cctv.append((i, j))
                    check[i][j] = True
                    cctv_n += 1
                if not board[i][j]:
                    ans += 1 # 최대 사각지대 구하기
        solution(0)
        print(ans)

     

    결과

     

    문제풀이나 코드에서 이상한 부분 지적은 언제나 환영합니다!

    댓글

Designed by Tistory.