이 포스팅은 프로그래머스 시리즈 28 편 중 27 번째 글 입니다.

  • Part 1 - 01: 다리를 지나는 트럭
  • Part 2 - 02: 멀정한 사각형
  • Part 3 - 03: 더 맵게
  • Part 4 - 04: 메뉴 리뉴얼
  • Part 5 - 05: 전화번호 목록
  • Part 6 - 06: 가장 큰 수
  • Part 7 - 07: 예상 대진표
  • Part 8 - 08: 다단계 칫솔 판매
  • Part 9 - 09: 불량 사용자
  • Part 10 - 10: 베스트 앨범
  • Part 11 - 11: 합승 택시 요금
  • Part 12 - 12: 스타 수열
  • Part 13 - 13: 위장
  • Part 14 - 14: 주식 가격
  • Part 15 - 15: 디스크 컨트롤러
  • Part 16 - 16: N으로 표현
  • Part 17 - 17: 전화번호 목록
  • Part 18 - 18: 단어 변환
  • Part 19 - 19: 여행 경로
  • Part 20 - 20: 프린터
  • Part 21 - 21: 후보키
  • Part 22 - 22: 삼각 달팽이
  • Part 23 - 23: 실패율
  • Part 24 - 24: 입국심사
  • Part 25 - 26: 기둥과 보 설치
  • Part 26 - 27: 광고 삽입
  • Part 27 - This Post
  • Part 28 - 29: 상호 평가
▼ 목록 보기

목차

▼ 내리기

풀이

하라는 대로 구현했다. 일단, board에서는 빈칸을 찾아야 하고, table에서는 채워진 조각을 찾아야 한다. 각각에서 그 빈 구석을 모두 도려낸 뒤에, 그 조각들이 맞는지를 완전탐색했다. 이 때, table에 있는 조각중, 사용을 마친 경우는 최종 결과물에 더해지면 안된다.

Code

import Foundation

let blocked = 2

struct Position {
    let y: Int
    let x: Int
    
    init(_ y: Int, _ x: Int) {
        self.y = y
        self.x = x
    }
}

class Block {
    var rowSize: Int
    var colSize: Int
    let fillCount: Int
    var isInserted: Bool = false
    var value: [[Int]]
    
    init(_ rowSize: Int, _ colSize: Int, _ fillCount: Int, _ value: [[Int]]) {
        self.rowSize = rowSize
        self.colSize = colSize
        self.fillCount = fillCount
        self.value = value
    }
    
    private func rotate(){
        var rotated = [[Int]]()
        for j in 0..<value[0].count {
            rotated.append(value.map({ $0[j] }).reversed())
        }
        self.value = rotated
        self.rowSize = rotated.count
        self.colSize = rotated[0].count
    }
    
    func isOk(_ rotated: Block, other block: Block) -> Bool {
        return rotated.rowSize == block.rowSize && rotated.colSize == block.colSize && rotated.fillCount == block.fillCount && rotated.isInserted == false && block.isInserted == false
    }
    
    func match(with block: Block) -> Int? {
        for _ in 0..<4 {
            self.rotate()
            if isOk(self, other: block) {
                if self.value == block.value {
                    self.isInserted = true
                    block.isInserted = true
                    return self.fillCount
                }
            }
        }
        return nil
    }
}



func BFS(start: Position, in board: inout [[Int]], with num: Int) -> Block? {
    let n = board.count
    func isOk(_ y: Int, _ x: Int) -> Bool {
        return (0..<n).contains(y) && (0..<n).contains(x) && board[y][x] == num
    }
    
    let d = [[1, 0], [0, 1], [-1, 0], [0, -1]]
    var q = Array([start])
    var positions = Array([start])
    board[start.y][start.x] = blocked
    
    while !q.isEmpty {
        guard let now = q.first else { return nil }
        q.removeFirst()
        let y = now.y, x = now.x
        
        for i in 0..<4 {
            let ny = y + d[i][0], nx = x + d[i][1]
            if isOk(ny, nx) {
                let position = Position(ny, nx)
                q.append(position)
                positions.append(position)
                board[ny][nx] = blocked
            }
        }
    }
    
    // 모인 positions에 대해서 row 상한 하한, col 상한 하한을 체크한다.
    let rowLowerBound = positions.map { $0.y }.min()!
    let rowUpperBound = positions.map { $0.y }.max()!
    let colLowerBound = positions.map { $0.x }.min()!
    let colUpperBound = positions.map { $0.x }.max()!
    
    var slicedBoard = board[rowLowerBound...rowUpperBound].map { Array($0[colLowerBound...colUpperBound]) }
    slicedBoard = slicedBoard.map({ $0.map( { $0 == blocked ? 1 : 0 })})
    return Block(slicedBoard.count, slicedBoard[0].count, positions.count, slicedBoard)
}

func detach(in board: inout [[Int]], with num: Int) -> [Block] {
    let n = board.count
    var blocks = [Block]()
    for i in 0..<n {
        for j in 0..<n {
            if board[i][j] == num {
                guard let block = BFS(start: Position(i, j), in: &board, with: num) else { continue }
                blocks.append(block)
            }
        }
    }
    return blocks
}


func solution(_ gameBoard:[[Int]], _ table:[[Int]]) -> Int {
    var board = gameBoard, table = table
    let boardBlocks = detach(in: &board, with: 0)
    let tableBlocks = detach(in: &table, with: 1)
    
    var count = 0
    for tBlock in tableBlocks {
        for bBlock in boardBlocks {
            if let matchCount = tBlock.match(with: bBlock) {
                count += matchCount
            }
        }
    }
    return count
}

Reference