본문 바로가기

백준 PS일지/Simulation

[백준/Swift] 15683 : 감시

 

 


15683 : 감시 / 문제 소개

 

문제는 이해하기 쉬웠다. 그렇지만 코드를 구현함에 있어서 그렇진 않았다....

 

사무실에는 K개의 CCTV가 설치되어 있다.

CCTV는 다섯가지다.

CCTV는 90도 방향으로 회전도 가능하다.

CCTV는 CCTV를 통과할 수 있다!!!

0 1 0 2 

0 0 0 0

0 0 0 0

이렇게 된다면

2가 가로 세로 방향일 때 1은 아래 방향이라하면

# 1 # 2

0 # 0 0

0 # 0 0

 이렇게 CCTV를 통과할 수 있다.

 

하지만 벽(6)은 통과할 수 없다.


사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.


풀이 과정

 

처음에 문제를 풀 때는 우선 특정 cctv좌표에서 상 하 좌 우 cctv시야 각을 다 저장한 다음에

Greedy하게 가장 큰 값을 선택해서 문제를 풀어나갔는데 나중엔 시야각이 같은 경우에도 무저건 이전것만 선택해서 답을 틀렸다.

 

그리고 가장 큰 값 말고 같은 큰 값도 다음 cctv탐색을 이어나갔는데 안됐다.

 

음 cctv 5번째는 상하 좌우 , 4는 3방향 ... 2는 2방향 으로 작아지니까 큰값부터 탐색해가면 ? 그래도 안됐다.

반대의 경우 작은 cctv시야 방향부터 1...5까지 cctv List를 정렬 후 탐색했는데도 안됐다.

4 6

2 6 0 3 0 2

0 0 0 0 0 0

0 0 0 0 0 0

0 0 0 0 6 1

correct = 8 wrong = 9

 

3 6

0 5 5 0 2 0

0 0 2 0 0 3

0 0 0 0 0 0

correct = 2 wrong 3

이 두가지의 경우에 막혔다.

 

아기 상어를 풀 때 처럼 Greedy하게? 풀어나갔는데 결국엔 모든 경우를 파악해야 풀 수 있는 문제임을 알게 됬다.

특정 cctv 종류에 따라 가장 많은 시야만!!! 탐색할 수 있는 방향을 선택해 다음 cctv좌표에서의 시야각을 탐색하지 않고,

시야가 최악의 경우까지 탐색을 계속해서 이어 나간 결과 맞을 수 있었다.

 

코드는 그냥 모든 경우를 다 탐색해나갔다.( 아 이렇게 힘겹게 풀어나간 사람도 있구나 하는 마음으로 봐주면 감사합니다. 코드구현이 좀 부족합니다.)

 

음 문제를 3시간 넘게 풀었는데 지금 다시보니 case에 따라서 탐색할 방향을 direction배열에 저장해도 좋을 것 같다는 생각이.. 들었다.(음 다른분의 코드를 보니 ㅋㅋㅋㅋ큼.)

 

//left == 0,right == 1,up == 2,down == 3
let direction   : [point] = [(-1,0),(1,0),(0,1),(0,-1)]

 

onCctv함수를 통해서 특정 방향(상 하 좌 우) 에 대해서 탐색할 수있는 시야를 -1로 처리를 했다.


코드 구현

 

import Foundation
typealias point = (x:Int,y:Int)
//left == 0,right == 1,up == 2,down == 3
let direction   : [point] = [(-1,0),(1,0),(0,1),(0,-1)]
class mapInfo
{
    let height   : Int
    let width    : Int
    var map      : [[Int]]
    var cctvList : [point]
    init()
    {
        let hw   = readLine()!.split(separator:" ").map{Int(String($0))!}
        height   = hw[0]
        width    = hw[1]
        map      = Array(repeating: [Int](), count: height)
        cctvList = [point]()
        for y in 0..<height
        {
            map[y] = readLine()!.split(separator:" ").map{Int(String($0))!}
            for x in 0..<width
            {
                if map[y][x] >= 1 && map[y][x] <= 5
                {
                    cctvList.append((x,y))
                }
            }
        }
    }
}
func onCctv(_ point : point, arrow i : Int, _ info : mapInfo,_ map : inout[[Int]]){
    let (cctvX,cctvY) = (point.x,point.y)
    
    var curX = cctvX, curY = cctvY
    while true
    {
        curX = curX + direction[i].x
        curY = curY + direction[i].y
        if curX < 0 || curX > info.width - 1 || curY < 0 || curY > info.height - 1 || info.map[curY][curX] == 6
        {
            break
        }
        else if map[curY][curX] == 0
        {
            map[curY][curX] = -1
        }
    }

}

func cctvWorking(_ index : Int,_ info : mapInfo, map : [[Int]], _ ans : inout Int)
{
    if index == info.cctvList.count
    {
        var count = 0
        for y in 0..<info.height
        {
            for x in 0..<info.width
            {
                if map[y][x] == 0
                {
                    count += 1
                }
            }
        }
        if count < ans
        {
            ans = count
            return
        }
        return
    }
    let (cctvX,cctvY) = info.cctvList[index]
    var m = map
    switch map[cctvY][cctvX]
    {
    case 1:
        for i in 0..<4
        {
            m = map
            onCctv((cctvX,cctvY), arrow: i, info, &m)
            cctvWorking(index + 1, info, map: m, &ans)
        }
        break;
    case 2:
        onCctv((cctvX,cctvY), arrow: 0, info,&m)
        onCctv((cctvX,cctvY), arrow: 1, info,&m)
        cctvWorking(index+1, info, map: m, &ans)
        var m2 = map
        onCctv((cctvX,cctvY), arrow: 2, info,&m2)
        onCctv((cctvX,cctvY), arrow: 3, info,&m2)
        cctvWorking(index+1, info, map: m2, &ans)
        break;
    case 3:
        onCctv((cctvX,cctvY), arrow: 0, info, &m)
        var m2 = m
        onCctv((cctvX,cctvY), arrow: 2, info,&m)
        cctvWorking(index+1, info, map: m, &ans)
        onCctv((cctvX,cctvY), arrow: 3, info, &m2)
        cctvWorking(index+1, info, map: m2, &ans)
        var m3 = map
        onCctv((cctvX,cctvY), arrow: 1, info,&m3)
        var m4 = m3
        onCctv((cctvX,cctvY), arrow: 2, info,&m3)
        cctvWorking(index+1, info, map: m3, &ans)
        onCctv((cctvX,cctvY), arrow: 3, info, &m4)
        cctvWorking(index+1, info, map: m4, &ans)
        break;
    case 4:
        var m2 = map
        var m3 = map
        var m4 = map
        onCctv((cctvX,cctvY), arrow: 0, info, &m)
        onCctv((cctvX,cctvY), arrow: 1, info, &m)
        onCctv((cctvX,cctvY), arrow: 2, info, &m)
        cctvWorking(index+1, info, map: m, &ans)
        onCctv((cctvX,cctvY), arrow: 0, info, &m2)
        onCctv((cctvX,cctvY), arrow: 1, info, &m2)
        onCctv((cctvX,cctvY), arrow: 3, info, &m2)
        cctvWorking(index+1, info, map: m2, &ans)
        onCctv((cctvX,cctvY), arrow: 0, info, &m3)
        onCctv((cctvX,cctvY), arrow: 2, info, &m3)
        onCctv((cctvX,cctvY), arrow: 3, info, &m3)
        cctvWorking(index+1, info, map: m3, &ans)
        onCctv((cctvX,cctvY), arrow: 1, info, &m4)
        onCctv((cctvX,cctvY), arrow: 2, info, &m4)
        onCctv((cctvX,cctvY), arrow: 3, info, &m4)
        cctvWorking(index+1, info, map: m4, &ans)
        break;
    case 5:
        onCctv((cctvX,cctvY), arrow: 0, info,&m)
        onCctv((cctvX,cctvY), arrow: 1, info,&m)
        onCctv((cctvX,cctvY), arrow: 2, info,&m)
        onCctv((cctvX,cctvY), arrow: 3, info,&m)
        cctvWorking(index+1, info, map: m, &ans)
        break;
    default:
        break;
    }
}

func BOJ_15683()
{
    var info = mapInfo()
    var index = 0
    var ans  = 9999999
    print(ans == 9999999 ? 0 : ans)

}
BOJ_15683()

 

visit my github