본문 바로가기

코딩테스트/백준

BOJ-14500 테트로미노 Swift (Brute-force)

문제

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다.

  • 정사각형은 서로 겹치면 안 된다.
  • 도형은 모두 연결되어 있어야 한다.
  • 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.

정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.

아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.

테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.

테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다.

입력

첫째 줄에 종이의 세로 크기 N과 가로 크기 M이 주어진다. (4 ≤ N, M ≤ 500)

둘째 줄부터 N개의 줄에 종이에 쓰여 있는 수가 주어진다. i번째 줄의 j번째 수는 위에서부터 i번째 칸, 왼쪽에서부터 j번째 칸에 쓰여 있는 수이다. 입력으로 주어지는 수는 1,000을 넘지 않는 자연수이다.

출력

첫째 줄에 테트로미노가 놓인 칸에 쓰인 수들의 합의 최댓값을 출력한다.

내가 푼 풀이

- 주어진 NxM종이에 테트로미노 하나 놓았을때의 합산 최댓값을 구하는 문제다.

- 테트로미노는 회전 및 대칭이 가능하다.

- 다른 특별한 규칙을 찾을 수 없어서 모든 경우의수를 찾는 방법을 택했다.

- 테트로미노를 회전과 대칭했을땐 규칙이 어느정도 보였고, 이를 구현했다.

- 배열을 순회하면서 모든 경우의수를 구하기위해 각 테트로미노에서 기준점을 정하고, 그 점을 기준으로 회전 및 대칭하였다.

 

기준점: X표시

1) 첫번째 테트로미노

첫번째 테트로미노는 대칭한 모습은 같고, 회전을 하면 4가지의 모형이 나온다.

하지만 배열을 순회하면서 최댓값을 구할때, 기준점 (0,0)과 기준점(0,3)의 180도 회전한 모습은 같은 최댓값을 갖는다.

따라서 첫번째 테트로미노는 두가지(0도, 90도) 모형으로 최댓값을 구한다.

 

 

2) 두번째 테트로미노

두번째 테트로미노는 대칭과 회전을해도 똑같은 모형이 나온다.

회전을 하면 기준점이 달라지지만, 이는 역시 배열 순회하면서 구한값을 다시 구하게 되므로 위와 같은 모형으로 구한다.

두번째 테트로미노는 한가지 모형으로 최댓값을 구한다.

 

 

3) 세번째 테트로미노

세번째 테트로미노는 회전 및 대칭하였을때 8가지의 모형이 나온다.

이 테트로미노는 배열을 순회하면서 모두 다른값이 나오므로 8가지 모형으로 최댓값을 구한다.

 

4) 네번째 테트로미노

네번째 테트로미노는 회전 및 대칭하였을때 4가지의 모형이 나온다.

이 4가지모형으로 최댓값을 구한다.

 

5) 다섯번째 테트로미노

다섯번째 테트로미노는 회전및 대칭해도 4가지의 모형이 나온다.

이 4가지모형으로 최댓값을 구한다.

 

위 모든 모형이 나올 수 있는 경우의수를 기준점을 기준으로 구한다.

 

코드로 구현하면 다음과 같다.

 

import Foundation

// 입력
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
let N = input[0], M = input[1]
var paper = [[Int]]()
var maxNum = Int.min
for i in 0..<N {
    paper.append(readLine()!.split(separator: " ").map{Int(String($0))!})
}

// 첫번째 테트로미노 경우의수
func poly1(x: Int, y: Int) {
    var sum = 0
    if x+3 >= M && y+3 >= N { return }
    if x+3 >= M {
        sum = paper[y][x] + paper[y+1][x] + paper[y+2][x] + paper[y+3][x]
        maxNum = max(maxNum, sum)
    } else if y+3 >= N {
        sum = paper[y][x] + paper[y][x+1] + paper[y][x+2] + paper[y][x+3]
        maxNum = max(maxNum, sum)
    } else {
        sum = paper[y][x] + paper[y+1][x] + paper[y+2][x] + paper[y+3][x]
        maxNum = max(maxNum, sum)
        sum = paper[y][x] + paper[y][x+1] + paper[y][x+2] + paper[y][x+3]
        maxNum = max(maxNum, sum)
    }
}

// 두번째 테트로미노 경우의수
func poly2(x: Int, y: Int) {
    var sum = 0
    if x+1 >= M || y+1 >= N { return }
    sum = paper[y][x] + paper[y+1][x] + paper[y][x+1] + paper[y+1][x+1]
    maxNum = max(maxNum, sum)
}

// 세번째 테트로미노 경우의수
func poly3(x: Int, y: Int) {
    var sum = 0
    if y-2 >= 0 {
        sum = paper[y][x] + paper[y-1][x] + paper[y-2][x]
        if x+1 < M {
            maxNum = max(maxNum, sum + paper[y][x+1])
        }
        if x-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y][x-1])
        }
    }
    if x+2 < M {
        sum = paper[y][x] + paper[y][x+1] + paper[y][x+2]
        if y+1 < N {
            maxNum = max(maxNum, sum + paper[y+1][x])
        }
        if y-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y-1][x])
        }
    }
    if y+2 < N {
        sum = paper[y][x] + paper[y+1][x] + paper[y+2][x]
        if x+1 < M {
            maxNum = max(maxNum, sum + paper[y][x+1])
        }
        if x-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y][x-1])
        }
    }
    if x-2 >= 0 {
        sum = paper[y][x] + paper[y][x-1] + paper[y][x-2]
        if y+1 < N {
            maxNum = max(maxNum, sum + paper[y+1][x])
        }
        if y-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y-1][x])
        }
    }
}

// 네번째 테트로미노 경우의수
func poly4(x: Int, y: Int) {
    var sum = 0
    if y-1 >= 0 {
        sum = paper[y][x] + paper[y-1][x]
        if x+1 < M && y+1 < N {
            maxNum = max(maxNum, sum + paper[y][x+1] + paper[y+1][x+1])
        }
        if x-1 >= 0 && y+1 < N {
            maxNum = max(maxNum, sum + paper[y][x-1] + paper[y+1][x-1])
        }
    }
    if x+1 < M {
        sum = paper[y][x] + paper[y][x+1]
        if y+1 < N && x-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y+1][x] + paper[y+1][x-1])
        }
        if y-1 >= 0 && x-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y-1][x] + paper[y-1][x-1])
        }
    }
}

// 다섯번째 테트로미노 경우의수
func poly5(x: Int, y:Int) {
    var sum = 0
    if x-1 >= 0 && x+1 < M {
        sum = paper[y][x-1] + paper[y][x] + paper[y][x+1]
        if y+1 < N {
            maxNum = max(maxNum, sum + paper[y+1][x])
        }
        if y-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y-1][x])
        }
    }
    if y-1 >= 0 && y+1 < N {
        sum = paper[y-1][x] + paper[y][x] + paper[y+1][x]
        if x+1 < M {
            maxNum = max(maxNum, sum + paper[y][x+1])
        }
        if x-1 >= 0 {
            maxNum = max(maxNum, sum + paper[y][x-1])
        }
    }
}

// 주어진 종이에서 기준점을 기준으로 모든 테트로미노 모형 경우의수를 따지고 최댓값을 구한다.
for i in 0..<N {
    for j in 0..<M {
        poly1(x: j, y: i)
        poly2(x: j, y: i)
        poly3(x: j, y: i)
        poly4(x: j, y: i)
        poly5(x: j, y: i)
    }
}

print(maxNum)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-1107 리모컨 Swift  (0) 2024.04.11
BOJ-1476 날짜 계산 Swift  (0) 2024.04.11
BOJ-1759 암호 만들기 Swift  (0) 2024.04.10
BOJ-1182 부분수열의 합 Swift  (0) 2024.04.10
BOJ-15686 치킨 배달 Swift  (0) 2024.04.10