https://www.acmicpc.net/problem/4574
4574번: 스도미노쿠
입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 채워져 있는 도미노의 개수 N이 주어진다. (10 ≤ N ≤ 35) 다음 N개 줄에는 도미노 하나를 나타내는 U LU V LV가
www.acmicpc.net
문제 풀이
1. sudomiku 배열을 선언하고 주어진 입력을 저장한다.
2. 완전 탐색을 수행한다. 이때 9 X 9 의 보드판이므로 완전 탐색의 depth 가 81이 되면 결과를 출력한다.
3. depth 81 인 경우가 여러 가지가 나올 수 있으므로 completed flag 를 설정하여 출력은 한 번 하면 다음번 depth(81) 조건을 만족하는 경우는 무시한다.
4. 도미노를 아래/오른쪽으로 회전하면서 완전 탐색한다. 위/왼쪽탐색은 무시하는 아래와 같이 도미노가 겹치기 때문에 2번만 회전하여 완전 탐색 한다.
4-1. (0, 1) 에 도미노를 아래 방향으로 회전해서 놓을 것과 (1, 1) 에 도미노를 위 방향으로 회전해서 놓은 것은 같다.
4-2. 마찬가지로 (1,0) 에 도미노를 오른쪽 방향으로 회전해서 놓은 것과 (1, 1)에 도미노를 왼쪽으로 회전해서 놓은 것은 같다.
5. 도미노에 들어갈 수 있는 숫자가 1 ~ 9 까지 이고 도미노는 인접한 두 개의 칸으로 이루어져 있으므로 이중 for 문을 이용해서 탐색한다.
5-1. 이중 for 문의 j = k 인 경우는 같은 숫자가 도미노로 구성되는 것으므로 다음 탐색을 한다.
5-2. sudominoku[newRow][newCol] 값이 0이 아니면 이미 숫자가 채워져 있으므로 다음 탐색을 한다.
5-3. domino[j][k] 가 1이 아니면 이미 도미노가 놓아져 있으므로 다음 탐색을 한다.
5-4. 놓을 숫자가 같은 행/열에 없는 지 그리고 3X3 사각형 내에서도 없는 지 확인한다.
6. 4, 5번의 탐색을 depth 가 81이 될 때까지 수행한다.
코드
import java.io.*
private val result = StringBuilder()
private var completed = false
fun main(args: Array<String>) {
val br = BufferedReader(InputStreamReader(System.`in`))
var T = 0
while (true) {
val N = br.readLine().toInt()
if (N == 0) break
result.append("Puzzle ${++T}\n")
val sudominoku = Array(9) { IntArray(9) { 0 } }
val domino = Array(10) { IntArray(10) { 0 } }
completed = false
repeat(N) {
val (num1, num1Position, num2, num2Position) = br.readLine().split(" ").map { it }
domino[num1.toInt()][num2.toInt()] = 1 // 도미노가 놓여져 있을 때 1로 업데이트 한다.
domino[num2.toInt()][num1.toInt()] = 1 // 도미노가 회전을 할 수 있으므로 양방향으로 저장한다.
val (x1, y1) = num1Position.map { it }
sudominoku[x1 - 'A'][y1.digitToInt() - 1] = num1.toInt()
val (x2, y2) = num2Position.map { it }
sudominoku[x2 - 'A'][y2.digitToInt() - 1] = num2.toInt()
}
val numPositionList = br.readLine().split(" ").map { it }
for ((index, position) in numPositionList.withIndex()) {
val (x, y) = position.map { it }
sudominoku[x - 'A'][y.digitToInt() - 1] = index + 1
}
/*println("===== Debug Print =====")
sudominoku.forEach { _sudomiku ->
_sudomiku.forEach {
print("$it ")
}
println()
}*/
dfs(sudominoku, domino, 0)
}
println(result.toString())
}
private fun dfs(sudominoku: Array<IntArray>, domino: Array<IntArray>, depth: Int) {
if (completed) {
return
}
if (!completed && depth == 81) {
completed = true
sudominoku.forEach { _sudomiku ->
_sudomiku.forEach {
result.append(it)
//print("$it")
}
result.append("\n")
//println()
}
return
}
val row = depth / 9
val col = depth % 9
if (sudominoku[row][col] == 0) {
// 도미노를 아래와 오른쪽에 대해서 각각 완전 탐색한다.
val dX = intArrayOf(1, 0)
val dY = intArrayOf(0, 1)
for (i in 0..1) {
val newRow = row + dX[i]
val newCol = col + dY[i]
// 1 ~ 9 중 도미노에 들어갈 수 있는 숫자를 확인한다.
for (j in 1..9) {
for (k in 1..9) {
// 같은 행/같은 열에 숫자가 없고
// 사용하지 않은 도미노 인지 확인한다.
// 도미노는 2개의 숫자가 인접해 있으므로 j, k 두 개의 수를 확인 한다.
// 같은 숫자이므로 다음 탐색을 한다.
if (j == k) continue
// 범위 밖이므로 다음 탐색을 한다.
if ((newRow < 0 || newRow >= 9 ) || (newCol < 0 || newCol >= 9)) continue
// 이미 숫자가 채워져 있으므로 다음 탐색을 한다.
if (sudominoku[newRow][newCol] != 0) continue
// 이미 사용한 도미노 이므로 다음 탐색을 한다.
if (domino[j][k] == 1) continue
if (check(sudominoku, row, col, j) && check(sudominoku, newRow, newCol, k)) {
sudominoku[row][col] = j
sudominoku[newRow][newCol] = k
domino[j][k] = 1
domino[k][j] = 1
dfs(sudominoku, domino, depth + 1)
sudominoku[row][col] = 0
sudominoku[newRow][newCol] = 0
domino[j][k] = 0
domino[k][j] = 0
}
}
}
}
} else {
// 이미 sudominoku 에 숫자가 채워져 있으므로 다음 탐색을 한다.
dfs(sudominoku, domino, depth + 1)
}
}
private fun check(sudominoku: Array<IntArray>, row: Int, col: Int, value: Int): Boolean {
for (i in 0..8) {
// 같은 행에 동일한 숫자가 있는 지 확인 한다.
if (sudominoku[row][i] == value) return false
// 같은 열에 동일한 숫자가 있는 지 확인 한다.
if (sudominoku[i][col] == value) return false
}
// 3X3에 같은 숫자가 있는 지 확인 한다.
val newX = (row / 3) * 3
val newY = (col / 3) * 3
for (i in newX until (newX + 3)) {
for (j in newY until (newY + 3)) {
if (sudominoku[i][j] == value) return false
}
}
return true
}
'알고리즘(w.KOTLIN) > 탐색' 카테고리의 다른 글
[백준][코틀린][12100] 2048 (0) | 2023.03.14 |
---|---|
[백준][코틀린][1062] 가르침 (0) | 2023.03.10 |
[백준][코틀린][14225] 부분수열의 합 (0) | 2023.03.10 |
[백준][코틀린][1987] 알파벳 (0) | 2023.03.09 |
[백준][코틀린][9663] N-Queen (0) | 2023.03.07 |