문제
5×5 크기의 숫자판이 있다. 각각의 칸에는 숫자(digit, 0부터 9까지)가 적혀 있다. 이 숫자판의 임의의 위치에서 시작해서, 인접해 있는 네 방향으로 다섯 번 이동하면서, 각 칸에 적혀있는 숫자를 차례로 붙이면 6자리의 수가 된다. 이동을 할 때에는 한 번 거쳤던 칸을 다시 거쳐도 되며, 0으로 시작하는 000123과 같은 수로 만들 수 있다.
숫자판이 주어졌을 때, 만들 수 있는 서로 다른 여섯 자리의 수들의 개수를 구하는 프로그램을 작성하시오.
입력 및 출력
- 입력: 다섯 개의 줄에 다섯 개의 정수로 숫자판이 주어진다.
- 출력: 첫째 줄에 만들 수 있는 수들의 개수를 출력한다.
풀이
숫자판을 모든 점에서 인접해 있는 네 방향으로 다섯 번 이동하면서 여섯자리 숫자를 얻어낸다. 숫자판을 이동하기 위해 DFS(깊이우선 탐색) 알고리즘을 통해 탐색한다.
보통 그래프 탐색을 할 때에는 visited배열을 두어 탐색한 곳을 저장해두어 다음에는 탐색한 곳을 재탐색하지 않도록하는데, 문제에서 한 번 거쳤던 점을 다시 거쳐도 된다고 하였으니 방문한 점은 고려하지 않아도 된다.
이렇게 찾은 여섯자리 숫자를 리스트에 모두 추가한다.
여섯 자리 숫자중 중복되는 숫자가 있을 수 있기 때문에 List-> Set으로 변경하고 그 개수를 세면 답을 얻을 수 있다.
코드
import java.io.BufferedWriter
import java.io.OutputStreamWriter
import java.util.*
val bw = BufferedWriter(OutputStreamWriter(System.out))
// 그래프 및 여섯자리 숫자를 받을 집합을 선언한다.
lateinit var graph: Array<IntArray>
lateinit var resultSet: MutableSet<String>
lateinit var tmp: MutableList<Char>
fun main() = with(System.`in`.bufferedReader()) {
// 그래프 초기화
graph = Array(5) { IntArray(5) {0} }
// DFS수행 중 완성된 6자리 숫자를 담을 리스트 초기화
tmp = MutableList<Char>(6){'0'}
// 집합 초기화
resultSet = mutableSetOf()
// 반복문을 통해 입력값을 그래프에 대입한다.
for(i in 0 until 5){
val list = readLine().split(" ").map{ it.toInt() }
for(j in list.indices) {
graph[i][j] = list[j]
}
}
// 모든 점에서 DFS 알고리즘을 수행한다.
for (i in 0 until 5) {
for (j in 0 until 5) {
dfs_2210(0, i, j)
}
}
// 결과 집합의 개수를 출력한다.
bw.write("${resultSet.size}")
bw.flush()
bw.close()
close()
}
fun dfs_2210(length: Int, x:Int, y:Int) {
// 1. 여섯자리가 완성 될 때
if(length == 6) {
val res = "${tmp[0]}${tmp[1]}${tmp[2]}${tmp[3]}${tmp[4]}${tmp[5]}"
resultSet.add(res)
} else { // 2. 그 이외
if (x < 0 || x >= graph.size || y < 0 || y >= graph[0].size)
return
tmp[length] = graph[x][y].toChar()
dfs_2210(length + 1, x, y - 1)
dfs_2210(length + 1, x, y + 1)
dfs_2210(length + 1, x - 1, y)
dfs_2210(length + 1, x + 1, y)
}
}
DFS 알고리즘
DFS 알고리즘이란 그래프를 탐색할 때 한 방향으로 갈 수 있을 때 까지 가다가 더 이상 갈 수 없게 되면 다시 가장 가까운 갈림길로 돌아와서 그곳으로부터 다시 다른 방향으로 갈 수 있을 떄까지 탐색을 반복하는 알고리즘이다.
본 문제에서는 다음과 같이 적용했다.
먼저 DFS가 실행되는 else절을 확인한다. (문제 조건 상 사방 탐색을 사용하였다.)
재귀함수를 통해 DFS를 구현할 수 있는데, 먼저, 현재 x, y좌표에서 (x, y-1)
방향으로 계속 탐색을 한다.
하단방향으로 탐색을 하다가 그래프 범위를 벗어났을 때, return을 하여, 다음 재귀함수를 실행하게 되고, (x, y+1)
우측 방향으로 계속 탐색을 한다.
(탐색을 하기 전에 먼저 tmp배열의 현재 좌표의 숫자를 기록하여 정답을 만들어가도록 하였다.)
이렇게 한 방향으로만 탐색을 하면서 글자를 추가해 나아가고 글자 수가 6이 되었을 때 length == 6
조건을 통해 결과를 도출한다.
결과
제한 메모리와 제한시간과 비교해보면 괜찮을 결과를 보인다.
'PS > BOJ' 카테고리의 다른 글
[BOJ-2824][백준 2824] 최대공약수[SILVER-1] [Solved by Kotlin] (0) | 2023.04.19 |
---|---|
[BOJ-1956][백준 1956] 운동[GOLD-4] [Solved by Kotlin] (0) | 2023.04.18 |
[BOJ-13701][백준 13701] 중복 제거 [GOLD-4] [Solved by Kotlin] (0) | 2023.04.17 |
[BOJ-1012][백준 1012] 유기농 배추 [SILVER-2] [Solved by Kotlin] (0) | 2023.04.14 |
[BOJ-4358][백준 4358] 생태학 [SILVER-2][Solve by Kotlin] (0) | 2023.04.12 |