백준 1780번 종이의 개수 - SWIFTAlgorithm/BOJ PS2024. 3. 13. 13:32
Table of Contents
문제
N×N크기의 행렬로 표현되는 종이가 있다. 종이의 각 칸에는 -1, 0, 1 중 하나가 저장되어 있다. 우리는 이 행렬을 다음과 같은 규칙에 따라 적절한 크기로 자르려고 한다.
- 만약 종이가 모두 같은 수로 되어 있다면 이 종이를 그대로 사용한다.
- (1)이 아닌 경우에는 종이를 같은 크기의 종이 9개로 자르고, 각각의 잘린 종이에 대해서 (1)의 과정을 반복한다.
이와 같이 종이를 잘랐을 때, -1로만 채워진 종이의 개수, 0으로만 채워진 종이의 개수, 1로만 채워진 종이의 개수를 구해내는 프로그램을 작성하시오.
입력
첫째 줄에 N(1 ≤ N ≤ 3^7, N은 3^k 꼴)이 주어진다. 다음 N개의 줄에는 N개의 정수로 행렬이 주어진다.
출력
첫째 줄에 -1로만 채워진 종이의 개수를, 둘째 줄에 0으로만 채워진 종이의 개수를, 셋째 줄에 1로만 채워진 종이의 개수를 출력한다.
문제 링크
풀이
백준 1074번 Z라는 문제랑 ▼
백준 1992번 쿼드트리라는 문제와 굉장히 비슷하다.▼
그 중에서도 쿼드트리라는 문제와 푸는 방식이 거의 똑같다.
먼저 전체 구간이 전부 같은 숫자로 되어있는지 확인하고, 9등분해서 각 등분을 똑같이 검사하면 된다.
전부 같은 숫자라면, 더 이상 탐색하지 않고 멈춘다.
이 재귀함수는 9갈래로 진행되기 때문에, 시간이 굉장히 오래걸려보이는데 최대 3^14만큼 호출된다고 보면된다.
대략 최대 10000000번 호출된다고 보면 된다.
프로그램 동작
1. 구간별로 숫자를 확인해본다.
2. 만약 전부 동일한 숫자가 아니라면, 9등분 한다.
만약 전부 동일한 숫자라면, 그 숫자에 맞게 정답 값을 늘려준다.
9등분은 아래의 수식과 같이 하면 된다.▼
3. 모든 갈래의 함수가 종료될 때 까지 1번과 2번을 반복한다.
Swift 코드
import Foundation
// 라이노님의 FileIO
final class FileIO {
private var buffer:[UInt8]
private var index: Int
init(fileHandle: FileHandle = FileHandle.standardInput) {
buffer = Array(fileHandle.readDataToEndOfFile())+[UInt8(0)]
index = 0
}
@inline(__always) private func read() -> UInt8 {
defer { index += 1 }
return buffer.withUnsafeBufferPointer { $0[index] }
}
@inline(__always) func readInt() -> Int {
var sum = 0
var now = read()
var isPositive = true
while now == 10
|| now == 32 { now = read() }
if now == 45{ isPositive.toggle(); now = read() }
while now >= 48, now <= 57 {
sum = sum * 10 + Int(now-48)
now = read()
}
return sum * (isPositive ? 1:-1)
}
@inline(__always) func readString() -> String {
var str = ""
var now = read()
while now == 10
|| now == 32 { now = read() }
while now != 10
&& now != 32 && now != 0 {
str += String(bytes: [now], encoding: .ascii)!
now = read()
}
return str
}
}
var file = FileIO()
let N = file.readInt()
var P = Array(repeating: Array(repeating: 0, count: N), count: N)
var A = Array(repeating: 0, count: 3)
for i in 0..<N {
for j in 0..<N {
P[i][j] = file.readInt()
}
}
func check(_ minY: Int, _ minX: Int, _ maxY: Int, _ maxX: Int) -> Bool {
for i in minY..<maxY {
for j in minX..<maxX {
if P[i][j] != P[minY][minX] {
return false
}
}
}
return true
}
func pick(_ minY: Int, _ minX: Int, _ maxY: Int, _ maxX: Int) {
if check(minY, minX, maxY, maxX) {
if P[minY][minX] == -1 {
A[0] += 1
} else if P[minY][minX] == 0 {
A[1] += 1
} else {
A[2] += 1
}
} else {
let y1 = minY, y2 = maxY
let x1 = minX, x2 = maxX
let dy = (maxY - minY) / 3, dx = (maxX - minX) / 3
pick(y1, x1, y2 - 2 * dy, x2 - 2 * dx)
pick(y1, x1 + dx, y2 - 2 * dy, x2 - dx)
pick(y1, x1 + 2 * dx, y2 - 2 * dy, x2)
pick(y1 + dy, x1, y2 - dy, x2 - 2 * dx)
pick(y1 + dy, x1 + dx, y2 - dy, x2 - dx)
pick(y1 + dy, x1 + 2 * dx, y2 - dy, x2)
pick(y1 + 2 * dy, x1, y2, x2 - 2 * dx)
pick(y1 + 2 * dy, x1 + dx, y2, x2 - dx)
pick(y1 + 2 * dy, x1 + 2 * dx, y2, x2)
}
}
pick(0, 0, N, N)
print(A[0])
print(A[1])
print(A[2])
'Algorithm > BOJ PS' 카테고리의 다른 글
백준 1920번 수 찾기 - SWIFT (0) | 2024.04.10 |
---|---|
백준 1865번 웜홀 - SWIFT (0) | 2024.04.02 |
백준 1069번 집으로 - C++ (0) | 2024.03.10 |
백준 1753번 최단경로 - SWIFT (0) | 2024.03.10 |
백준 1747번 소수&팰린드롬 - SWIFT (0) | 2024.03.03 |
@노근 :: NOGUEN 블로그