
Problem
์ฝ๋ฉํ ์คํธ ์ฐ์ต - ๋ธ๋ก ์ด๋ํ๊ธฐ
[[0, 0, 0, 1, 1],[0, 0, 0, 1, 0],[0, 1, 0, 1, 1],[1, 1, 0, 0, 1],[0, 0, 0, 0, 0]] 7
programmers.co.kr
Solution
ํด๋น ๋ฌธ์ ๋ BFS๋ก ํ์ด์ผํ๋ ๋ฌธ์ ์ ๋๋ค.
1. ํ์ฌ ์์น, ์์ง์ผ ๋ช ๋ น, ๋ฐฉํฅ์ ์ด๊ธฐํํด์ค๋๋ค.
struct Current {
var x:Int,y:Int,d:Direction,count:Int,past:Command
}
enum Command:CaseIterable {
case up,down,left,right,rotateClockwise,rotateAntiClockwise,rotateClockwise2,rotateAntiClockwise2
}
enum Direction:CaseIterable {
case right,down,left,up
}
ํ์ฌ ์์น๋ x,y,๋ฐฉํฅ,์๊ฐ,๊ณผ๊ฑฐ์ ์์ง์ธ ๋ช ๋ น์ ํ๋กํผํฐ๋ก ๊ฐ์ง๋๋ค.
๋ช ๋ น์ ์,์๋,์ผ์ชฝ,์ค๋ฅธ์ชฝ๊ณผ ๋ก๋ด์ ์ฒซ๋ฒ์งธ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๊ณ๋ฐฉํฅ,๋ฐ์๊ณ ๋ฐฉํฅ,๋๋ฒ์งธ๋ฅผ ๊ธฐ์ค์ผ๋ก ์๊ณ๋ฐฉํฅ,๋ฐ์๊ณ๋ฐฉํฅ
์ด 8๊ฐ์ง์ ๋ช ๋ น์ ์ค์ ํด์ค๋๋ค.
(์๋์ฒ๋ผ ๋ก๋ด์ 1๋ฒ์งธ์ 2๋ฒ์งธ๋ผ๊ณ ๋ถ๋ฅด๊ฒ ์ต๋๋ค.)

๋ฐฉํฅ์ ํ์ฌ ๋ก๋ด์ 1๋ฒ์งธ ๊ธฐ์ค์ผ๋ก ๋๋ฒ์งธ ๋ก๋ด์ด ์ด๋ ๋ฐฉํฅ์ ์๋์ง๋ฅผ ๋ํ๋ ๋๋ค.

2. ๋ช ๋ น์ ๋ฐ๋ผ ํ์ฌ ์์น๋ฅผ ์์ง์ฌ์ค๋๋ค.
//๋ช
๋ น์ ๋ฐ๋ผ ์์ง์ธ ์์น๋ฅผ ๋ฐํ
func move(current:Current,command:Command) -> Current {
var newCurrent = current
let allDirection = Direction.allCases
let index = allDirection.firstIndex(of: current.d) ?? -1
switch command {
case .up:
newCurrent.y -= 1
case .down:
newCurrent.y += 1
case .left:
newCurrent.x -= 1
case .right:
newCurrent.x += 1
case .rotateClockwise:
newCurrent.d = index == 3 ? .right:allDirection[index+1]
case .rotateAntiClockwise:
newCurrent.d = index == 0 ? .up:allDirection[index-1]
case .rotateClockwise2:
newCurrent = current2(current: current)
newCurrent.d = index == 0 ? .up :allDirection[index-1]
case .rotateAntiClockwise2:
newCurrent = current2(current: current)
newCurrent.d = index == 3 ? .right :allDirection[index+1]
}
return newCurrent
}
3. ์ด๋ํ ์์น๊ฐ ๊ฐ๋ฅํ ์์น์ ์๋์ง ํ์ธํด์ค๋๋ค.
์ฐ์ ํ์ฌ ์์น๊ฐ ์ง๋ ๋ด์ ์๋์ง ํ์ธํ๊ณ
ํ์ฌ ์์น๊ฐ 1์ด ์๋์ง ํ์ธํ๊ณ
ํ์ฌ ์์น๊ฐ ์ด๋ฏธ ๋ฐฉ๋ฌธํ ์์น๊ฐ ์๋์ง ์ด๋ ๊ฒ ์ด 3๊ฐ์ง๋ฅผ ํ์ธํฉ๋๋ค.
์ฌ๊ธฐ์ ๋ง์ฝ ํ์ฌ ์์น์ ๊ณผ๊ฑฐ๊ฐ ํ์ ํด์ ๋์ฐฉํ ์์น๋ผ๋ฉด
๊ฐ ๋งจํํผ ๊ฑฐ๋ฆฌ๊ฐ 1์ด ์๋์๋์ง ํ์ธํด์ค๋๋ค.
//์ด๋ํ ์์น๊ฐ ๊ฐ๋ฅํ ์์น์ธ์ง ํ์ธ
func isEnabled(current:Current,b:[[Int]]) -> Bool {
let second = current2(current: current)
//ํ์ฌ ๋ก๋ด์ด ์ง๋ ๋ด์ ์๋์ง ํ์ธ
if 0..<b.count ~= current.x && 0..<b.count ~= current.y && 0..<b.count ~= second.x && 0..<b.count ~= second.y {
//ํ์ฌ ๋ก๋ด์ด ์๋ ๊ณณ์ด ๋ชจ๋ 0์ธ์ง ํ์ธ
if b[current.y][current.x] == 0 && b[second.y][second.x] == 0 {
//ํ์ฌ ๋ก๋ด์ด ์๋ ๊ณณ์ด ์ด๋ฏธ ์ง๋๊ฐ ๊ณณ์ด ์๋์ง ํ์ธ
if !dontMove[current.d]![current.y][current.x] {
//์๊ณ๋ฐฉํฅ์ผ๋ก ํ์ ํ์ ๊ฒฝ์ฐ ๊ฐ ํ์ฌ ์์น ๋งจํํผ ๊ฑฐ๋ฆฌ๊ฐ 0์ธ์ง ํ์ธ
if current.past == .rotateClockwise || current.past == .rotateClockwise2{
return b[current.y+clockManhattan[current.d]!.1][current.x+clockManhattan[current.d]!.0] == 0
//๋ฐ์๊ณ๋ฐฉํฅ์ผ๋ก ํ์ ํ์ ๊ฒฝ์ฐ ๊ฐ ํ์ฌ ์์น ๋งจํํผ ๊ฑฐ๋ฆฌ๊ฐ 0์ธ์ง ํ์ธ
}else if current.past == .rotateAntiClockwise || current.past == .rotateAntiClockwise2{
return b[current.y+antiClockManhattan[current.d]!.1][current.x+antiClockManhattan[current.d]!.0] == 0
}else {
return true
}
}
}
}
return false
}
4. BFS๋ฅผ ์ด์ฉํด์ ์ง๋์ ๋งจ ๋์ ๋์ฐฉํ ๋๊น์ง ๋ฐ๋ณตํด์ค๋๋ค.
ํ๋ฅผ ์ด์ฉํด์ ํ์ฌ ์์น๋ฅผ ๋ด๊ณ ๋ก๋ด์ด ๊ฐ๋ฅํ ์์น์ ์๋์ง ํ์ธํ๊ณ
๊ฐ๋ฅํ๋ค๋ฉด ๋ชจ๋ ๋ช ๋ น์ ๋ฐ๋ผ ์์ง์ด๊ฒ ํ๊ณ ํ์ ๋ด์์ค ๋ค
์ง๋์ ๋งจ ๋์ ๋ก๋ด์ด ๋์ฐฉํ๋ค๋ฉด ํด๋น ์๊ฐ์ ๋ฐํํด์ค๋๋ค.
func findMinCountByBFS(board:[[Int]]) -> Int {
let allCommand = Command.allCases
var queue:[Current] = [Current(x: 0, y: 0, d: .right, count: 0, past: .right)]
while !queue.isEmpty {
var first = queue.removeFirst()
let second = current2(current: first)
if isEnabled(current: first, b: board) {
if (first.x == board.count-1 && first.y == board.count-1) || (second.x == board.count-1 && second.y == board.count-1){
return first.count
}
//๋ฐฉ๋ฌธ ํ์
dontMove[first.d]![first.y][first.x] = true
//์นด์ดํธ 1์ฆ๊ฐ
first.count += 1
//๋ช
๋ น๋ณ๋ก ์์ง์ฌ์ค
for command in allCommand {
var newCurrent = move(current: first, command: command)
newCurrent.past = command
queue.append(newCurrent)
}
}
}
return 0
}
Source Code
struct Current { | |
var x:Int,y:Int,d:Direction,count:Int,past:Command | |
} | |
enum Command:CaseIterable { | |
case up,down,left,right,rotateClockwise,rotateAntiClockwise,rotateClockwise2,rotateAntiClockwise2 | |
} | |
enum Direction:CaseIterable { | |
case right,down,left,up | |
} | |
//์ด๋ฏธ ๋ฐฉ๋ฌธํ ๊ณณ์ ๋ฐฉํฅ๋ณ๋ก ์ ์ฅ | |
var dontMove:[Direction:[[Bool]]] = [:] | |
//์๊ณ ๋ฐฉํฅ ํ์ ์ ๋งจํํผ๊ฑฐ๋ฆฌ | |
let clockManhattan:[Direction:(Int,Int)] = [.up:(-1,-1),.down:(+1,+1),.left:(-1,+1),.right:(+1,-1)] | |
//๋ฐ์๊ณ ๋ฐฉํฅ ํ์ ์ ๋งจํํผ๊ฑฐ๋ฆฌ | |
let antiClockManhattan:[Direction:(Int,Int)] = [.up:(+1,-1),.down:(-1,+1),.left:(-1,-1),.right:(+1,+1)] | |
//๋ฐฉํฅ์ ๋ฐ๋ฅธ ๋๋ฒ์งธ ๋ก๋ด ์์น | |
let directionXY:[Direction:(Int,Int)] = [.up:(0,-1),.down:(0,+1),.left:(-1,0),.right:(+1,0)] | |
func solution(_ board:[[Int]]) -> Int { | |
Direction.allCases.forEach{ | |
dontMove[$0] = Array(repeating: Array(repeating: false, count: board.count), count: board.count) | |
} | |
return findMinCountByBFS(board: board) | |
} | |
func findMinCountByBFS(board:[[Int]]) -> Int { | |
let allCommand = Command.allCases | |
var queue:[Current] = [Current(x: 0, y: 0, d: .right, count: 0, past: .right)] | |
while !queue.isEmpty { | |
var first = queue.removeFirst() | |
let second = current2(current: first) | |
if isEnabled(current: first, b: board) { | |
if (first.x == board.count-1 && first.y == board.count-1) || (second.x == board.count-1 && second.y == board.count-1){ | |
return first.count | |
} | |
//๋ฐฉ๋ฌธ ํ์ | |
dontMove[first.d]![first.y][first.x] = true | |
//์นด์ดํธ 1์ฆ๊ฐ | |
first.count += 1 | |
//๋ช ๋ น๋ณ๋ก ์์ง์ฌ์ค | |
for command in allCommand { | |
var newCurrent = move(current: first, command: command) | |
newCurrent.past = command | |
queue.append(newCurrent) | |
} | |
} | |
} | |
return 0 | |
} | |
//๋ช ๋ น์ ๋ฐ๋ผ ์์ง์ธ ์์น๋ฅผ ๋ฐํ | |
func move(current:Current,command:Command) -> Current { | |
var newCurrent = current | |
let allDirection = Direction.allCases | |
let index = allDirection.firstIndex(of: current.d) ?? -1 | |
switch command { | |
case .up: | |
newCurrent.y -= 1 | |
case .down: | |
newCurrent.y += 1 | |
case .left: | |
newCurrent.x -= 1 | |
case .right: | |
newCurrent.x += 1 | |
case .rotateClockwise: | |
newCurrent.d = index == 3 ? .right:allDirection[index+1] | |
case .rotateAntiClockwise: | |
newCurrent.d = index == 0 ? .up:allDirection[index-1] | |
case .rotateClockwise2: | |
newCurrent = current2(current: current) | |
newCurrent.d = index == 0 ? .up :allDirection[index-1] | |
case .rotateAntiClockwise2: | |
newCurrent = current2(current: current) | |
newCurrent.d = index == 3 ? .right :allDirection[index+1] | |
} | |
return newCurrent | |
} | |
//์ด๋ํ ์์น๊ฐ ๊ฐ๋ฅํ ์์น์ธ์ง ํ์ธ | |
func isEnabled(current:Current,b:[[Int]]) -> Bool { | |
let second = current2(current: current) | |
//ํ์ฌ ๋ก๋ด์ด ์ง๋ ๋ด์ ์๋์ง ํ์ธ | |
if 0..<b.count ~= current.x && 0..<b.count ~= current.y && 0..<b.count ~= second.x && 0..<b.count ~= second.y { | |
//ํ์ฌ ๋ก๋ด์ด ์๋ ๊ณณ์ด ๋ชจ๋ 0์ธ์ง ํ์ธ | |
if b[current.y][current.x] == 0 && b[second.y][second.x] == 0 { | |
//ํ์ฌ ๋ก๋ด์ด ์๋ ๊ณณ์ด ์ด๋ฏธ ์ง๋๊ฐ ๊ณณ์ด ์๋์ง ํ์ธ | |
if !dontMove[current.d]![current.y][current.x] { | |
//์๊ณ๋ฐฉํฅ์ผ๋ก ํ์ ํ์ ๊ฒฝ์ฐ ๊ฐ ํ์ฌ ์์น ๋งจํํผ ๊ฑฐ๋ฆฌ๊ฐ 0์ธ์ง ํ์ธ | |
if current.past == .rotateClockwise || current.past == .rotateClockwise2{ | |
return b[current.y+clockManhattan[current.d]!.1][current.x+clockManhattan[current.d]!.0] == 0 | |
//๋ฐ์๊ณ๋ฐฉํฅ์ผ๋ก ํ์ ํ์ ๊ฒฝ์ฐ ๊ฐ ํ์ฌ ์์น ๋งจํํผ ๊ฑฐ๋ฆฌ๊ฐ 0์ธ์ง ํ์ธ | |
}else if current.past == .rotateAntiClockwise || current.past == .rotateAntiClockwise2{ | |
return b[current.y+antiClockManhattan[current.d]!.1][current.x+antiClockManhattan[current.d]!.0] == 0 | |
}else { | |
return true | |
} | |
} | |
} | |
} | |
return false | |
} | |
//๋ฐฉํฅ์ ๋ฐ๋ผ ๋๋ฒ์งธ ๋ก๋ด ์์น ๋ฐํ | |
func current2(current:Current) -> Current { | |
var newCurrent = current | |
newCurrent.x += directionXY[current.d]!.0 | |
newCurrent.y += directionXY[current.d]!.1 | |
return newCurrent | |
} |
ํ๊ธฐ
์ด๋ฒ ๋ฌธ์ ๋ ํ 3์ผ๋์ ํ์๋ ๋ฌธ์ ๋ค...
๋ฌธ์ ๋ฅผ ๋ณด์๋ง์ BFS๋ก ํ๋ฉด ๊ธ๋ฐฉ ํ๋ฆฌ๊ฒ ๋ค? ํ๊ณ ํ์๋๋ฐ
๊ตฌํ๊ณผ์ ์์ ์ด๋ ๊ฒ ์ด๋ ค์์ ๊ฒช์๊ฑด ์ฒ์์ด์๋ค..
์ฒ์์ x1,y1,x2,y2๋ก ์ค์ ํด๋๊ณ ๋ก๋ด์ ์์ง์ด๋ คํ๋ ํ์ ์ ๋ฐ๋ผ ์ฝ๋ ๊ตฌํ์ด ์์ฒญ ๋ณต์กํด์ง๊ณ ํ๋๋ผ๋
๋์น๋ฉด ์ด๋์ ํ๋ ธ๋์ง ํ์ธํ๋ ์๊ฐ์ด ์ค๋๊ฑธ๋ ธ๋ค.. ์ฒ์๋ถํฐ ๋ฐฉํฅ์ผ๋ก ์ค์ ํ๋ค๋ฉด ๊ธ๋ฐฉ ํ์์ํ ๋ฐ..
๋ํ ํ ์คํธ์ผ์ด์ค 1๋ฒ์ด ๊ณ์ ํ๋ ค์ ์ ํ๋ฆฌ๋์ง ์ด๋ค ์ผ์ด์ค์ธ์ง ํ์ธํ๋ ค๋ ๊ณผ์ ์ด ์ค๋ ๊ฑธ๋ ธ๋ค...
๊ฒฐ๊ตญ ์์๋๋๋ฐ ํ ์คํธ์ผ์ด์ค 1๋ฒ์ ๋ก๋ด์ด ์ง๋ ๋งจ ๋์ ๋์ฐฉํ์ ๋ ๊ฐ๋ฅํ ์์น์ ์๋์ง ์๋์ง ํ์ธํด์ผํ๋ค.
ex)
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 r1 r2
0 0 0 1 0
์๋์ ๊ฐ์ด ๋ก๋ด์ด ์๋ค๋ฉด ๋ง์ง๋ง์ ์๋๋ก ์ด๋ํ ๊ฒฝ์ฐ ๊ฐ์ฅ ๋งจ ๋์ ์ด๋ํ ์ ์๋ค.
ํ์ง๋ง r1์ 1์ด ์์ผ๋ฏ๋ก ๋์ฐฉํ๋ค ํ๋๋ผ๋ ๊ฐ๋ฅํ์ง ์ฌ๋ถ๋ฅผ ํ์ ํด์ผํ๋ค.
'๐ Problem Solution > Programmers' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Swift] 2018 KAKAO BLIND RECRUITMENT [1์ฐจ] ์ ํ๋ฒ์ค (0) | 2021.08.06 |
---|---|
[Swift] 2020 KAKAO INTERNSHIP ๋ณด์ ์ผํ (0) | 2021.08.04 |
[Swift] 2019 KAKAO WINTER INTERNSHIP ์ง๊ฒ๋ค๋ฆฌ ๊ฑด๋๊ธฐ (0) | 2021.07.23 |
[Swift] 2021 KAKAO INTERNSHIP ์ซ์ ๋ฌธ์์ด๊ณผ ์๋จ์ด (0) | 2021.07.18 |
[Swift] 2021 KAKAO INTERNSHIP ํํธ์ง (0) | 2021.07.18 |
๋๊ธ