πŸ’†πŸ»β€β™‚οΈ ν”Ό-μ—μŠ€/🐣 ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

[μŠ€μœ„ν”„νŠΈ μ•Œκ³ λ¦¬μ¦˜] 경주둜 건섀

κ°œλ°œν•˜λŠ” ν›ˆμ΄ 2021. 10. 24. 00:52

문제

https://programmers.co.kr/learn/courses/30/lessons/67259

 

μ½”λ”©ν…ŒμŠ€νŠΈ μ—°μŠ΅ - 경주둜 건섀

[[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0],[0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0],[0,0,0,1,0,0,0,1],[0,0,1,0,0,0,1,0],[0,1,0,0,0,1,0,0],[1,0,0,0,0,0,0,0]] 3800 [[0,0,1,0],[0,0,0,0],[0,1,0,1],[1,0,0,0]] 2100 [[0,0,0,0,0,0],[0,1,1,1,1,0],[0,0,1,0,0,0],[1,0,0,1,0,1],[

programmers.co.kr

 

문제 μ„€λͺ…

κ±΄μ„€νšŒμ‚¬μ˜ 섀계사인 μ£ λ₯΄λ””λŠ” κ³ κ°μ‚¬λ‘œλΆ€ν„° μžλ™μ°¨ 경주둜 건섀에 ν•„μš”ν•œ 견적을 μ˜λ’°λ°›μ•˜μŠ΅λ‹ˆλ‹€.
제곡된 경주둜 섀계 도면에 λ”°λ₯΄λ©΄ 경주둜 λΆ€μ§€λŠ” N x N ν¬κΈ°μ˜ μ •μ‚¬κ°ν˜• 격자 ν˜•νƒœμ΄λ©° 각 κ²©μžλŠ” 1 x 1 ν¬κΈ°μž…λ‹ˆλ‹€.
섀계 λ„λ©΄μ—λŠ” 각 격자의 칸은 0 λ˜λŠ” 1 λ‘œ μ±„μ›Œμ Έ 있으며, 0은 칸이 λΉ„μ–΄ μžˆμŒμ„ 1은 ν•΄λ‹Ή 칸이 벽으둜 μ±„μ›Œμ Έ μžˆμŒμ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
경주둜의 μΆœλ°œμ μ€ (0, 0) μΉΈ(쒌츑 상단)이며, 도착점은 (N-1, N-1) μΉΈ(우츑 ν•˜λ‹¨)μž…λ‹ˆλ‹€. μ£ λ₯΄λ””λŠ” 좜발점인 (0, 0) μΉΈμ—μ„œ μΆœλ°œν•œ μžλ™μ°¨κ°€ 도착점인 (N-1, N-1) μΉΈκΉŒμ§€ λ¬΄μ‚¬νžˆ 도달할 수 있게 쀑간에 λŠκΈ°μ§€ μ•Šλ„λ‘ 경주둜λ₯Ό 건섀해야 ν•©λ‹ˆλ‹€.


κ²½μ£Όλ‘œλŠ” 상, ν•˜, 쒌, 우둜 μΈμ ‘ν•œ 두 빈 칸을 μ—°κ²°ν•˜μ—¬ 건섀할 수 있으며, 벽이 μžˆλŠ” μΉΈμ—λŠ” 경주둜λ₯Ό 건섀할 수 μ—†μŠ΅λ‹ˆλ‹€.
μ΄λ•Œ, μΈμ ‘ν•œ 두 빈 칸을 μƒν•˜ λ˜λŠ” 쒌우둜 μ—°κ²°ν•œ 경주둜λ₯Ό μ§μ„  λ„λ‘œ λΌκ³  ν•©λ‹ˆλ‹€.


λ˜ν•œ 두 μ§μ„  λ„λ‘œκ°€ μ„œλ‘œ 직각으둜 λ§Œλ‚˜λŠ” 지점을 μ½”λ„ˆ λΌκ³  λΆ€λ¦…λ‹ˆλ‹€.


건섀 λΉ„μš©μ„ 계산해 λ³΄λ‹ˆ μ§μ„  λ„λ‘œ ν•˜λ‚˜λ₯Ό λ§Œλ“€ λ•ŒλŠ” 100원이 μ†Œμš”λ˜λ©°, μ½”λ„ˆλ₯Ό ν•˜λ‚˜ λ§Œλ“€ λ•ŒλŠ” 500원이 μΆ”κ°€λ‘œ λ“­λ‹ˆλ‹€.
μ£ λ₯΄λ””λŠ” κ²¬μ μ„œ μž‘μ„±μ„ μœ„ν•΄ 경주둜λ₯Ό κ±΄μ„€ν•˜λŠ” 데 ν•„μš”ν•œ μ΅œμ†Œ λΉ„μš©μ„ 계산해야 ν•©λ‹ˆλ‹€.

 

예λ₯Ό λ“€μ–΄, μ•„λž˜ 그림은 μ§μ„  λ„λ‘œ 6κ°œμ™€ μ½”λ„ˆ 4개둜 κ΅¬μ„±λœ μž„μ˜μ˜ 경주둜 μ˜ˆμ‹œμ΄λ©°, 건섀 λΉ„μš©μ€ 6 x 100 + 4 x 500 = 2600원 μž…λ‹ˆλ‹€.

또 λ‹€λ₯Έ 예둜, μ•„λž˜ 그림은 μ§μ„  λ„λ‘œ 4κ°œμ™€ μ½”λ„ˆ 1개둜 κ΅¬μ„±λœ 경주둜이며, 건섀 λΉ„μš©μ€ 4 x 100 + 1 x 500 = 900원 μž…λ‹ˆλ‹€.


λ„λ©΄μ˜ μƒνƒœ(0은 λΉ„μ–΄ 있음, 1은 λ²½)을 λ‚˜νƒ€λ‚΄λŠ” 2차원 λ°°μ—΄ boardκ°€ λ§€κ°œλ³€μˆ˜λ‘œ μ£Όμ–΄μ§ˆ λ•Œ, 경주둜λ₯Ό κ±΄μ„€ν•˜λŠ”λ° ν•„μš”ν•œ μ΅œμ†Œ λΉ„μš©μ„ return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μ™„μ„±ν•΄μ£Όμ„Έμš”.

 

풀이

이 λ¬Έμ œλŠ” κ·Έλž˜ν”„ 탐색과 λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ°μ„ ν•¨κ»˜ μ‚¬μš©ν•΄μ•Ό μ‹œκ°„μ΄ˆκ³Όλ₯Ό ν”Όν•  수 μžˆλŠ” λ¬Έμ œμ˜€μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ 각 μœ„μΉ˜μ— λŒ€ν•œ μ΅œμ†Œ λΉ„μš©μ„ 계속 κ°±μ‹ ν•˜λ©΄μ„œ ν˜„μž¬ μ΅œμ†Œ λΉ„μš©λ³΄λ‹€ 큰 λΉ„μš©μ΄ κ±Έλ¦¬λŠ” 지점을 λ§Œλ‚¬μ„ λ•ŒλŠ” 더 이상 탐색을 μ§„ν–‰ν•˜μ§€ μ•Šλ„λ‘ ν•΄μ„œ μ—°μ‚°νšŸμˆ˜λ₯Ό μ΅œμ†Œν™” ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

예λ₯Ό λ“€λ©΄, A -> B -> C νƒμƒ‰κ²½λ‘œ, D -> B -> C 의 νƒμƒ‰κ²½λ‘œκ°€ μžˆμ„ λ•Œ, 경둜 A-B-Cμ—μ„œμ˜ Bμ§€μ μ˜ μ΅œμ†ŒλΉ„μš©μ΄ 100이고, DBCλ₯Ό 탐색할 λ•Œ B의 μ΅œμ†ŒλΉ„μš©μ΄ 200이라면, λ‚˜λ¨Έμ§€ Cλ₯Ό 탐색할 ν•„μš”μ—†μ΄ 이미 μ΅œμ†ŒλΉ„μš©μ„ λ§Œλ“€ 수 μ—†μŒμ„ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ 각 μ§€μ μ˜ μ΅œμ†ŒλΉ„μš©μ„ 계속 μ €μž₯ν•˜λ©΄μ„œ κ°±μ‹ ν•˜λŠ” DP 배열을 ν•„μš”λ‘œ ν•©λ‹ˆλ‹€.

 

λ˜ν•œ λ¬Έμ œμ—μ„œ μ½”λ„ˆλΉ„μš©μ— λŒ€ν•œ μ‘°κ±΄λ•Œλ¬Έμ— λ°œμƒν•˜λŠ” μ˜ˆμ™Έμƒν™©μ΄ μžˆμŠ΅λ‹ˆλ‹€. μ–΄λ–€ μ§€μ μ—μ„œ μ–΄λ–€ λ°©ν–₯을 μ„ νƒν•˜λŠ”μ§€μ— λ”°λΌμ„œ μ΅œμ†ŒλΉ„μš©μ΄ 달라지기 λ•Œλ¬Έμ—, λͺ¨λ“  λ°©ν–₯에 λŒ€ν•œ μ΅œμ†ŒλΉ„μš©μ„ μ•Œκ³ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. λ”°λΌμ„œ DP 배열을 각 λ°©ν–₯에 λŒ€ν•΄ 4개λ₯Ό μ„€μ •ν•΄μ„œ λ°©ν–₯에 λŒ€ν•œ μ΅œμ†ŒλΉ„μš©μ„ λͺ¨λ‘ κΈ°λ‘ν•΄μ•Όν•©λ‹ˆλ‹€.

μ½”λ“œ

import Foundation
func solution(_ board:[[Int]]) -> Int {
enum Direction: Int {
case down, up, right, left;
}
let costs = Array(repeating: Array(repeating: 987654321, count: board.count), count: board.count)
var dirCosts = Array(repeating: costs, count: 4)
for i in 0..<4 {
dirCosts[i][0][0] = 0
}
func isInRange(x: Int, y: Int) -> Bool {
return x >= 0 && x < board.count && y >= 0 && y < board.count
}
func dfs(_ x: Int, _ y: Int, _ currDir: Direction) {
let xDir = [0, 0, 1, -1]
let yDir = [1, -1, 0, 0]
let dirs:[Direction] = [.down, .up, .right, .left]
for i in 0..<4 {
let nextX = x + xDir[i]
let nextY = y + yDir[i]
let nextDir = dirs[i]
let costNext = dirCosts[currDir.rawValue][x][y] + (currDir == nextDir ? 100 : 600)
guard isInRange(x: nextX, y: nextY) == true,
dirCosts[i][nextX][nextY] > costNext else { continue }
dirCosts[i][nextX][nextY] = costNext
if board[nextX][nextY] != 1 {
dfs(nextX, nextY, nextDir)
}
}
}
dfs(0, 0, .up)
dfs(0, 0, .left)
dfs(0, 0, .right)
dfs(0, 0, .down)
return dirCosts.map({ $0[board.count - 1][board.count - 1] }).min() as! Int
}