본문 바로가기
Algorithm

(BOJ) 15683 감시 golang

by snwo 2022. 5. 9.
package main

import (
    "bufio"
    "fmt"
    "os"
)

type XY struct {
    x int
    y int
}

var dx = []int{-1, 0, 1, 0}
var dy = []int{0, 1, 0, -1}
var w = bufio.NewWriter(os.Stdout)
var r = bufio.NewReader(os.Stdin)
var N, M int
var board, board2 [10][10]int

func pad(x, y, dir int) {
    dir %= 4
    for 1 == 1 {
        x += dx[dir]
        y += dy[dir]
        if 0 > x || x >= N || 0 > y || y >= M || board2[x][y] == 6 { // reach the wall
            break
        }
        if board2[x][y] != 0 { // there is a cctv, able to get through
            continue
        }
        board2[x][y] = 7
    }
}

func main() {
    prev := 0
    var cctv []XY = make([]XY, 0, 8)
    defer w.Flush()
    fmt.Fscan(r, &N, &M)
    for i := 0; i < N; i++ {
        for j := 0; j < M; j++ {
            fmt.Fscan(r, &board[i][j])
            if board[i][j] == 0 {
                prev += 11
            } else if board[i][j] > 0 && board[i][j] < 6 {
                cctv = append(cctv, XY{i, j})
            }
        }
    }
    // fmt.Fprintln(w, cctv)
    // fmt.Fprint(w, board)
    for k := 0; k < 1<<(2*len(cctv)); k++ { // 4진수로 모든 방향 탐색
        ans := 0
        kk := k
        for i := range board {
            for j, value := range board[i] {
                board2[i][j] = value
            }
        }
        for c := 0; c < len(cctv); c++ { // 4진수 각 자리별로 cctv 의 방향을 나타냄
            dir := kk % 4
            kk /= 4
            x := cctv[c].x
            y := cctv[c].y
            switch board2[x][y] {
            case 1:
                pad(x, y, dir)
            case 2:
                pad(x, y, dir)
                pad(x, y, dir+2)
            case 3:
                pad(x, y, dir)
                pad(x, y, dir+1)
            case 4:
                pad(x, y, dir)
                pad(x, y, dir+1)
                pad(x, y, dir+2)
            case 5:
                pad(x, y, dir)
                pad(x, y, dir+1)
                pad(x, y, dir+2)
                pad(x, y, dir+3)
            }
        }
        // fmt.Fprintln(w, board2)
        for i := 0; i < N; i++ { // 0 개수 카운트
            for j := 0; j < M; j++ {
                if board2[i][j] == 0 {
                    ans += 1
                }
            }
        }
        if ans < prev {
            prev = ans
            ans = prev
        }
    }
    fmt.Fprintln(w, prev)

}

먼저, ans 값을 빈칸 갯수 (0) 으로 설정해놓는다.

입력받으면서 cctv 좌표를 배열에 넣는다.

$4^k (k=cctv)$ 만큼 반복문을 돌며,

각 자리수가 방향을 나타내게 한다

ex : ) cctv 개수 : 4

0000
0001
0002
0003
0010
0011
...
3333

각 cctv 의 방향대로 board2 에 7로 채운다

벽은 통과할 수 없으므로 break 하고

cctv 는 통과할 수 있으니 continue 해준다

그동안 배웠던 알고리즘 활용하는거는 약간 어려워서 바킹독님 강의 많이 참고했다. 백트래킹 대신 4진수를 쓰는 아이디어가 신기했다