Skip to content

Commit 1b54fcc

Browse files
committed
[level 3] Title: [카카오 인턴] 경주로 건설, Time: 83.05 ms, Memory: 16.8 MB -BaekjoonHub
1 parent b71b755 commit 1b54fcc

2 files changed

Lines changed: 203 additions & 0 deletions

File tree

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# [level 3] [카카오 인턴] 경주로 건설 - 67259
2+
3+
[문제 링크](https://school.programmers.co.kr/learn/courses/30/lessons/67259?language=swift)
4+
5+
### 성능 요약
6+
7+
메모리: 16.8 MB, 시간: 83.05 ms
8+
9+
### 구분
10+
11+
코딩테스트 연습 > 2020 카카오 인턴십
12+
13+
### 채점결과
14+
15+
정확성: 100.0<br/>합계: 100.0 / 100.0
16+
17+
### 제출 일자
18+
19+
2025년 02월 14일 18:34:14
20+
21+
### 문제 설명
22+
23+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/384b9e2a-4eb5-460d-bce2-d12359b03b14/kakao_road1.png" title="" alt="kakao_road1.png"></p>
24+
25+
<p>건설회사의 설계사인 <code>죠르디</code>는 고객사로부터 자동차 경주로 건설에 필요한 견적을 의뢰받았습니다.<br>
26+
제공된 경주로 설계 도면에 따르면 경주로 부지는 <code>N x N</code> 크기의 정사각형 격자 형태이며 각 격자는 <code>1 x 1</code> 크기입니다.<br>
27+
설계 도면에는 각 격자의 칸은 <code>0</code> 또는 <code>1</code> 로 채워져 있으며, <code>0</code>은 칸이 비어 있음을 <code>1</code>은 해당 칸이 벽으로 채워져 있음을 나타냅니다.<br>
28+
경주로의 출발점은 (0, 0) 칸(좌측 상단)이며, 도착점은 (N-1, N-1) 칸(우측 하단)입니다. 죠르디는 출발점인 (0, 0) 칸에서 출발한 자동차가 도착점인 (N-1, N-1) 칸까지 무사히 도달할 수 있게 중간에 끊기지 않도록 경주로를 건설해야 합니다.<br>
29+
경주로는 상, 하, 좌, 우로 인접한 두 빈 칸을 연결하여 건설할 수 있으며, 벽이 있는 칸에는 경주로를 건설할 수 없습니다.<br>
30+
이때, 인접한 두 빈 칸을 상하 또는 좌우로 연결한 경주로를 <code>직선 도로</code> 라고 합니다.<br>
31+
또한 두 <code>직선 도로</code>가 서로 직각으로 만나는 지점을 <code>코너</code> 라고 부릅니다.<br>
32+
건설 비용을 계산해 보니 <code>직선 도로</code> 하나를 만들 때는 100원이 소요되며, <code>코너</code>를 하나 만들 때는 500원이 추가로 듭니다.<br>
33+
죠르디는 견적서 작성을 위해 경주로를 건설하는 데 필요한 최소 비용을 계산해야 합니다.</p>
34+
35+
<p>예를 들어, 아래 그림은 <code>직선 도로</code> 6개와 <code>코너</code> 4개로 구성된 임의의 경주로 예시이며, 건설 비용은 6 x 100 + 4 x 500 = 2600원 입니다.</p>
36+
37+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/0e0911e8-f88e-44fe-8bdc-6856a56df8e0/kakao_road2.png" title="" alt="kakao_road2.png"></p>
38+
39+
<p>또 다른 예로, 아래 그림은 <code>직선 도로</code> 4개와 <code>코너</code> 1개로 구성된 경주로이며, 건설 비용은 4 x 100 + 1 x 500 = 900원 입니다.</p>
40+
41+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/3f5d9c5e-d7d9-4248-b111-140a0847e741/kakao_road3.png" title="" alt="kakao_road3.png"></p>
42+
43+
<hr>
44+
45+
<p>도면의 상태(0은 비어 있음, 1은 벽)을 나타내는 2차원 배열 board가 매개변수로 주어질 때, 경주로를 건설하는데 필요한 최소 비용을 return 하도록 solution 함수를 완성해주세요.</p>
46+
47+
<h5><strong>[제한사항]</strong></h5>
48+
49+
<ul>
50+
<li>board는 2차원 정사각 배열로 배열의 크기는 3 이상 25 이하입니다.</li>
51+
<li>board 배열의 각 원소의 값은 0 또는 1 입니다.
52+
53+
<ul>
54+
<li>도면의 가장 왼쪽 상단 좌표는 (0, 0)이며, 가장 우측 하단 좌표는 (N-1, N-1) 입니다.</li>
55+
<li>원소의 값 0은 칸이 비어 있어 도로 연결이 가능함을 1은 칸이 벽으로 채워져 있어 도로 연결이 불가능함을 나타냅니다.</li>
56+
</ul></li>
57+
<li>board는 항상 출발점에서 도착점까지 경주로를 건설할 수 있는 형태로 주어집니다.</li>
58+
<li>출발점과 도착점 칸의 원소의 값은 항상 0으로 주어집니다.</li>
59+
</ul>
60+
61+
<hr>
62+
63+
<h5><strong>입출력 예</strong></h5>
64+
<table class="table">
65+
<thead><tr>
66+
<th>board</th>
67+
<th>result</th>
68+
</tr>
69+
</thead>
70+
<tbody><tr>
71+
<td>[[0,0,0],[0,0,0],[0,0,0]]</td>
72+
<td>900</td>
73+
</tr>
74+
<tr>
75+
<td>[[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]]</td>
76+
<td>3800</td>
77+
</tr>
78+
<tr>
79+
<td>[[0,0,1,0],[0,0,0,0],[0,1,0,1],[1,0,0,0]]</td>
80+
<td>2100</td>
81+
</tr>
82+
<tr>
83+
<td>[[0,0,0,0,0,0],[0,1,1,1,1,0],[0,0,1,0,0,0],[1,0,0,1,0,1],[0,1,0,0,0,1],[0,0,0,0,0,0]]</td>
84+
<td>3200</td>
85+
</tr>
86+
</tbody>
87+
</table>
88+
<h5><strong>입출력 예에 대한 설명</strong></h5>
89+
90+
<p><strong>입출력 예 #1</strong></p>
91+
92+
<p>본문의 예시와 같습니다.</p>
93+
94+
<p><strong>입출력 예 #2</strong></p>
95+
96+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/ccc72e9c-2e22-4a09-a94b-ff057b081a70/kakao_road4.png" title="" alt="kakao_road4.png"></p>
97+
98+
<p>위와 같이 경주로를 건설하면 <code>직선 도로</code> 18개, <code>코너</code> 4개로 총 3800원이 듭니다.</p>
99+
100+
<p><strong>입출력 예 #3</strong></p>
101+
102+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/422e86e0-a7d7-4a09-9b42-2b6218a9b5f0/kakao_road5.png" title="" alt="kakao_road5.png"></p>
103+
104+
<p>위와 같이 경주로를 건설하면 <code>직선 도로</code> 6개, <code>코너</code> 3개로 총 2100원이 듭니다.</p>
105+
106+
<p><strong>입출력 예 #4</strong></p>
107+
108+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/4fe42f47-2592-4cb8-91fb-31d6a6da8639/kakao_road6.png" title="" alt="kakao_road6.png"></p>
109+
110+
<p>붉은색 경로와 같이 경주로를 건설하면 <code>직선 도로</code> 12개, <code>코너</code> 4개로 총 3200원이 듭니다.<br>
111+
만약, 파란색 경로와 같이 경주로를 건설한다면 <code>직선 도로</code> 10개, <code>코너</code> 5개로 총 3500원이 들며, 더 많은 비용이 듭니다.</p>
112+
113+
<hr>
114+
115+
<p>※ 공지 - 2021년 8월 30일 테스트케이스가 추가되었습니다.</p>
116+
117+
118+
> 출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import Foundation
2+
3+
enum Direction {
4+
case U
5+
case D
6+
case L
7+
case R
8+
}
9+
10+
class Queue<T> {
11+
var queue = [T?]()
12+
var head = 0
13+
var isEmpty: Bool {
14+
queue.count - head == 0
15+
}
16+
var front: T? {
17+
isEmpty ? nil : queue[head]
18+
}
19+
func enqueue(_ element: T) {
20+
queue.append(element)
21+
}
22+
func dequeue() -> T? {
23+
if isEmpty { return nil }
24+
let ret = queue[head]
25+
queue[head] = nil
26+
head += 1
27+
return ret
28+
}
29+
}
30+
31+
func calcCost(_ currentDirection: Direction, _ nextDirection: Direction, _ currentCost: Int) -> Int {
32+
if [.L, .R].contains(currentDirection) && [.U, .D].contains(nextDirection) {
33+
return currentCost + 600
34+
}
35+
if [.U, .D].contains(currentDirection) && [.L, .R].contains(nextDirection){
36+
return currentCost + 600
37+
}
38+
return currentCost + 100
39+
}
40+
41+
func BFS(_ board:[[Int]], _ direction: Direction) -> Int {
42+
typealias PosCost = (Int, Int, Int, Direction) // y, x, preCost, direction
43+
44+
let dx = [0, 0, -1, 1]
45+
let dy = [-1, 1, 0, 0]
46+
let dir: [Direction] = [.U, .D, .L, .R]
47+
48+
let queue = Queue<PosCost>()
49+
let start = (0, 0, 0, direction)
50+
51+
var visitCost = [[Int]](repeating: [Int](repeating: Int.max, count: board.count), count: board.count)
52+
var answer = Int.max
53+
54+
queue.enqueue(start)
55+
56+
while !queue.isEmpty {
57+
let cur = queue.dequeue()!
58+
if cur.0 == board.count - 1 && cur.1 == board.count - 1 {
59+
answer = min(answer, cur.2)
60+
continue
61+
}
62+
(0..<4).forEach { i in
63+
let nextDirection = dir[i]
64+
let cost = calcCost(cur.3, nextDirection, cur.2)
65+
let next = (cur.0 + dy[i], cur.1 + dx[i], cost, nextDirection)
66+
guard next.0 < board.count && next.0 > -1 && next.1 < board.count && next.1 > -1 else { return }
67+
guard board[next.0][next.1] == 0 else { return }
68+
guard visitCost[next.0][next.1] > cost else { return }
69+
// 현재에 저장하지 않고 다음에 저장하는 이유는
70+
// 지금까지의 경로는 직선도로 n개 + 코너 m개를 저장한 후
71+
// 다른 경로와 이 경로를 비교할 때 그 경로까지의 직선도로와 코너의 수를
72+
// 비교해도 무방하기 때문이다.
73+
// 다음 칸에 저장하지만, 지금까지의 정보가 들어있는 셈
74+
// 마지막 칸은 도로를 건설하지 않기 때문에 가능하기도 하다.
75+
visitCost[next.0][next.1] = cost
76+
queue.enqueue(next)
77+
}
78+
}
79+
return answer
80+
}
81+
82+
func solution(_ board:[[Int]]) -> Int {
83+
let answer = min(BFS(board, .L), BFS(board, .D))
84+
return answer
85+
}

0 commit comments

Comments
 (0)