Algorithm/BOJ
백준 17070 파이프 옮기기 1
삼쓰 웅쓰
2021. 4. 20. 12:38
728x90
출처: www.acmicpc.net/problem/17070
분류: DP, 백트래킹
접근방식
주어진 요구사항 대로 파이프의 이동 가능 위치를 잘 계산하고 나면 백트래킹으로 도착한 경우의 수를 세주면 되는 문제였습니다.
파이프의 끝 점에서 출발한 경로는 역시 다시 방문해줄 필요가 없으므로 방향을 고려한 3차원 배열에 이를 기록해서 방문 횟수를 줄여줬습니다.
조금 귀찮긴 하지만 크게 어렵지는 않아서 풀이를 보시면 이해가 되실거에요 :)
해결방법
let n = Int(readLine()!)!
var map = [[Int]]()
for _ in 0..<n {
map.append(readLine()!.split(separator: " ").map { Int(String($0))! })
}
enum Direction: Int {
case horizontal = 0
case vertical
case diagonal
}
typealias Point = (r: Int, c: Int)
typealias Pipe = (Point, Point)
func direction(_ pipe: Pipe) -> Direction {
if pipe.0.r == pipe.1.r, abs(pipe.0.c - pipe.1.c) == 1 {
return .horizontal
} else if pipe.0.c == pipe.1.c, abs(pipe.0.r - pipe.1.r) == 1 {
return .vertical
} else {
return .diagonal
}
}
func next(_ pipe: Pipe) -> [Pipe] {
var nextPipes = [Pipe]()
let dir = direction(pipe)
if dir == .horizontal || dir == .diagonal {
if 0..<n ~= pipe.1.c+1, map[pipe.1.r][pipe.1.c+1] != 1 {
nextPipes.append(Pipe(pipe.1, (pipe.1.r, pipe.1.c+1)))
}
}
if dir == .vertical || dir == .diagonal {
if 0..<n ~= pipe.1.r+1, map[pipe.1.r+1][pipe.1.c] != 1 {
nextPipes.append(Pipe(pipe.1, (pipe.1.r+1, pipe.1.c)))
}
}
if 0..<n ~= pipe.1.r+1, 0..<n ~= pipe.1.c+1,
map[pipe.1.r+1][pipe.1.c] != 1,
map[pipe.1.r][pipe.1.c+1] != 1,
map[pipe.1.r+1][pipe.1.c+1] != 1 {
nextPipes.append(Pipe(pipe.1, (pipe.1.r+1, pipe.1.c+1)))
}
return nextPipes
}
var dpMap = [[[Int]]](repeating: [[Int]](repeating: [Int](repeating: -1, count: 3), count: n), count: n)
func move(_ pipe: Pipe) -> Int {
let dir = direction(pipe).rawValue
guard dpMap[pipe.1.r][pipe.1.c][dir] == -1 else { return dpMap[pipe.1.r][pipe.1.c][dir] }
dpMap[pipe.1.r][pipe.1.c][dir] = 0
if pipe.1.r == n-1, pipe.1.c == n-1 {
dpMap[pipe.1.r][pipe.1.c][dir] = 1
return dpMap[pipe.1.r][pipe.1.c][dir]
}
for p in next(pipe) {
dpMap[pipe.1.r][pipe.1.c][dir] += move(p)
}
return dpMap[pipe.1.r][pipe.1.c][dir]
}
print(move(((0,0), (0,1))))