Algorithm/BOJ

백준 15683 감시

삼쓰 웅쓰 2020. 7. 16. 13:29
728x90

출처: www.acmicpc.net/problem/15683

분류: 완전탐색


접근방식

하.. 코드량이 너무 너무 너무 길었던 문제였습니다.

5개의 CCTV가 있고 각 CCTV는 90도로 회전이 가능합니다.
사각지대가 가장 최소가 되는 경우를 찾는 문제입니다.

각 CCTV 의 케이스는
1번 상하좌우 4개
2번 상하, 좌우 2개
3번 4개
4번 4개
5번 1개

입니다. 

저는 CCTV를 먼저 찾아놓고 CCTV List를 다 탐색할 때 까지 DFS를 돌렸습니다.

CCTV 에 케이스는 많지만 결국 지우는 건 방향에 따라 상하좌우 4가지 이므로 상하좌우 direction을 입력받는 함수를 만들어서 지우고
CCTV 타입별로 상 하 좌 우로 직접 입력해주는 방식을 사용했습니다.

더 스마트하게 풀 수도 있을 것 같은데 좀 무식하게 푼 것 같네요ㅠ
board를 계속 복사해서 그런지 시간이 꽤 걸렸네요..
어렵다기보다는 꽤나 귀찮았던 문제였습니다.

 

해결방법

let nm = readLine()!.split(separator: " ").map{Int($0)!}
var board = [[Int]]()
for _ in 0..<nm[0] {
    board.append(readLine()!.split(separator: " ").map({Int($0)!}))
}
var minBlindArea = Int.max
typealias CCTV = (r: Int, c: Int, type: Int)
enum Direction {
    case up
    case down
    case right
    case left
}
var cctvList = [CCTV]()

for r in 0..<board.count {
    for c in 0..<board[0].count {
        if board[r][c] == 0 || board[r][c] == 6 { continue }
        cctvList.append(CCTV(r: r, c: c, type: board[r][c]))
    }
}

func makeSafeArea(row: Int, col: Int, direction: Direction, board: [[Int]]) -> [[Int]] {
    var r = row
    var c = col
    var board = board
    
    switch direction {
    case .up:
        while 0..<board.count ~= r-1  {
            r -= 1
            if board[r][c] == 6 {
                return board
            } else if board[r][c] == 0 {
                board[r][c] = -1
            } else {
                continue
            }
        }
        return board
    case .down:
        while 0..<board.count ~= r+1  {
            r += 1
            if board[r][c] == 6 {
                return board
            } else if board[r][c] == 0 {
                board[r][c] = -1
            } else {
                continue
            }
        }
        return board
    case .left:
        while 0..<board[0].count ~= c-1  {
            c -= 1
            if board[r][c] == 6 {
                return board
            } else if board[r][c] == 0 {
                board[r][c] = -1
            } else {
                continue
            }
        }
        return board
    case .right:
        while 0..<board[0].count ~= c+1  {
            c += 1
            if board[r][c] == 6 {
                return board
            } else if board[r][c] == 0 {
                board[r][c] = -1
            } else {
                continue
            }
        }
        return board
    }
}

func checked(cctv: CCTV, board: [[Int]]) -> [[[Int]]] {
    var boards = [[[Int]]]()
    switch cctv.type {
    case 1:
        boards.append(makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: board))
        boards.append(makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: board))
        boards.append(makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: board))
        boards.append(makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: board))
    case 2:
        var leftBoard = board
        leftBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: leftBoard)
        leftBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: leftBoard)
        boards.append(leftBoard)
        
        var upDownBoard = board
        upDownBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: upDownBoard)
        upDownBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: upDownBoard)
        boards.append(upDownBoard)
    case 3:
        var tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: tempBoard)
        boards.append(tempBoard)
        
        tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: tempBoard)
        boards.append(tempBoard)
        
        tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: tempBoard)
        boards.append(tempBoard)
        
        tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: tempBoard)
        boards.append(tempBoard)
    case 4:
        var tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: tempBoard)
        boards.append(tempBoard)
        
        tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: tempBoard)
        boards.append(tempBoard)
        
        tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: tempBoard)
        boards.append(tempBoard)
        
        tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: tempBoard)
        boards.append(tempBoard)
    case 5:
        var tempBoard = board
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .left, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .up, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .right, board: tempBoard)
        tempBoard = makeSafeArea(row: cctv.r, col: cctv.c, direction: .down, board: tempBoard)
        boards.append(tempBoard)
    default: break
    }
    return boards
}

func check(index: Int, board origin: [[Int]]) {
    if index >= cctvList.count {
        var blind = 0
        for row in origin {
            blind += row.filter({ $0 == 0 }).count
        }
        minBlindArea = min(minBlindArea, blind)
        return
    }
    
    let cctv = cctvList[index]
    for board in checked(cctv: cctv, board: origin) {
        check(index: index+1, board: board)
    }
}
check(index: 0, board: board)
print(minBlindArea)

 

배운점

하아... 진빠진다..