14503 : 로봇 청소기 / 문제 소개
로봇은 NxM 크기의 직사각형 안에서 청소를 한다.
로봇 청소기는 청소기가 바라보는 방향이 있다. ( 북, 동, 남, 서 ) 중 1
청소를 할 때 규칙이 있다.
1. 현재 위치를 청소한다.
2.현재 위치에서 로봇이 바라보는 방향의 왼쪽 방향부터 차례대로 청소할 곳이 있는지 탐색한다.
탐색 조건은
2-1. 왼쪽 방향에 아직 청소하지 않은 공간 존재 -> 그 방향으로 회전 후 한칸 전진 후 1. 진행
2-2. 왼쪽 방향 청소 없다면 왼쪽 회전 후 2번으로 돌아감.
2-3. 네 방향 모두 청소 되어있거나 벽인 경우, 현재 위치에서 바라보는 방향의 반대 방향으로 한 칸 후진한다. 이때 바라보는 방향은 유지
2-4. 네 방향 모두 청소 되어있거나, 벽 or 더 이상 후진 할 수 없는 경우 작동을 멈춘다.
input
첫째 줄 : 세로 가로 크기
둘째 줄 : 로봇 청소기 좌표, 바라보는 방향(0 : 북, 1 : 동, : 2 : 남, 3 : 서)
셋째 ~ N : 맵 정보
풀이 과정
이 문제를 보며 간과한 부분이 2개가 있었습니다.
1. 청소기가 바라보는 방향이 d == 0부터 북 서 남 동이 아니라 북 동 남 서
2. 후진 시 벽일 경우 뿐 아니라 더 이상 후진 할 수 없는 경우(맵을 벗어난 경우)
두가지 조건을 기억 하면서 문제를 풀어 나가야 합니다.
주어진 입력의 초기 로봇 청소기 방향에 따라서 정답이 달라집니다.
로봇 청소기의 방향에 따라 청소 할 수 있는 경로와 결과가 달라지기 때문입니다.
이 문제의 핵심은 방향 정하는 것 같습니다.
로봇이 앞을 바라보는 방향( == front로 부르겠습니다.)이
- 북쪽 일 때 90도 = 서
- 동쪽 일 때 90도 = 북
- 남쪽 일 때 90도 = 동
- 서쪽 일 때 90도 = 남
로봇이 바라보는 (front 시야)방향이 아래 그림1과 같을 때
탐색할 수 있는 경우는
case 1. 왼쪽에 청소할 공간이 있을때, (좌)
case 2. case1의 경우 왼쪽이 벽이거나 탐색했을 때 (아래)
case 3. case1 과 case2가 안되서 로봇이 아래쪽 시야를 바라볼 때 (우)
case 4. case1, case2 일때 탐색한 이후 후진해서 다시 돌아온 상태이거나, 벽인 경우 (위)
그래서 d == 0일때! d==0에 기준을 두어
특정 좌표에 대해서 앞으로 탐색해 나갈 좌표는 90도씩 회전한 방향의 좌표를 갖도록
//바라보는 방향에 따라 왼쪽으로 전진
let direction = [(-1,0),(0,-1),(1,0),(0,1)]
이제 로봇의 방향이 d==0일때
d == 0이면 해당 좌표에 direction[0]을 .
case1이 안되서 case2로 전환한 경우 front(로봇 방향) == 좌 이면
해당 좌표에 + direction[1]
case2가 안되서 case3으로 전환한 경우 front == 아래
이면 해당 좌표에 + direction[2]
case 1도 x, case 2도 x case 3도 x case 4이면
해당 좌표에 direction[3]을 더해감으로 d == 0일 때 탐색 방향을 정할 수 있습니다.
d == 1( 로봇이 오른쪽을 바라봄)이라면?
direction[1] , 이 방향이 막히면 direection[2] , 이 방향이 막히거나 청소한 경우면 direction[3], 청소하거나 막히면 direction[0]을 더해줌으로써 청소할 곳을 90도씩 회전하며 탐색해 나갈수 있습니다.
d==2 (아래) 면 현재 좌표에 direction[2] , 청소하거나 벽이거나 맵 밖인 경우, direction[3], 청소하거나 벽이거나 맵 밖인 경우 direction[0], 청소하거나 벽이거나 맵 밖인 경우direction[1]
d== 3도, d==4도 마찬가지입니다. 마찬가지입니다.
따라서 저는 dfs탐색 시 매개변수로 받은 좌표는 현재 방문했으면서 문제에서 주어진 2번 조건을 적용시켜야 함으로
특정 front일 때.
front == 1이면 direction[1] 부터 2, 3, 0
fornt == 2이면 direciton[2] 부터 3,4,0,1
...
func DFS(_ x : Int, _ y : Int, _ front : Int, _ clean : inout Int, _ m : mapInfo, _ visited : inout [[Bool]])
{
var index = front
for _ in 0..<4
{
let (dx,dy) = direction[index]
index -= 1
if index == -1
{
index = 3
}
let (nx,ny) = (x+dx,y+dy)
.
.
.
이렇게 구해갔습니다.
또 중요한 게 있습니다.
로봇이 특정 방향으로부터 90도씩 회전하여 다시 특정 방향으로 갔다는 것은 더이상 청소를 할 곳이 없다는 뜻이므로 문제의 조건에 따라
후진을 해주어야 합니다.
후진 도 마찬가지로 d==0에 기준을 두어 설정했습니다.
let backDirect = [(0,1),(-1,0),(0,-1),(1,0)]
문제의 조건을 코드에 잘 적용 시켰다면
input
6 6
2 1 3
1 1 1 1 1 1
1 0 0 0 0 1
1 0 1 1 1 1
1 0 1 1 1 1
1 0 1 1 1 1
1 1 1 1 1 1
ans : 7 (5 아님)
input
12 9
0 0 0
0 0 0 1 1 0 0 0 1
0 0 1 0 0 0 0 1 1
1 0 1 0 0 0 0 0 1
1 0 0 0 1 1 0 1 1
0 0 1 1 1 0 0 0 1
0 1 1 1 1 0 1 0 1
1 0 1 1 1 0 0 1 1
0 0 0 0 1 0 0 1 1
1 0 0 0 0 0 0 1 1
1 0 1 1 0 1 1 1 0
1 1 0 1 1 1 0 1 0
1 0 1 1 1 1 1 0 0
출처: https://joey09.tistory.com/122 [joie de vivre:티스토리]
ans : 5
답이 나올 것입니다.
코드 구현
import Foundation
//바라보는 방향에 따라 왼쪽으로 전진
let direction = [(-1,0),(0,-1),(1,0),(0,1)]
//바라보는 방향에 반대로 후진
let backDirect = [(0,1),(-1,0),(0,-1),(1,0)]
//맵 정보
class mapInfo
{
let width : Int
let height : Int
var map : [[Int]]
let start : (x : Int, y : Int, direct : Int)
init()
{
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
height = input[0]
width = input[1]
let sPoint = readLine()!.split(separator:" ").map{Int(String($0))!}
start = (sPoint[1], sPoint[0], sPoint[2])
map = Array(repeating: [Int](),count: height)
for y in 0..<height
{
map[y] = readLine()!.split(separator: " ").map{Int(String($0))!}
}
}
}
/**
dfs탐색
- parameter x: 현재 청소 할 x좌표.
- parameter y: 현재 청소 할 y좌표.
- parameter front: 로봇 청소기가 바라보는 방향.
- parameter clean: 청소 누적 횟수.
- parameter m: 맵 정보.
# Notes: #
1. 매개변수x,y 를 통해 현재 좌표에서 로봇이 바라보는 방향 front의 왼쪽 방향으로 회전 후 청소할 공간이 있을 때 전진하며 청소를 진행해간다.
2. 바라보는 방향에서 90도 회전을 4번했는데 더이상 청소할 공간이 없다면
3. 바라보는 방향 front에 대한 back 작업을 진행한다.
4. 주의할 점이 맵의 벽이 1로 둘러진 경우만 생각할 게 아니라 맵의 0 0 좌표 일때도 로봇이 존재할 경우가 있다. 예외처리를 잘 해주어야 한다.
*/
func DFS(_ x : Int, _ y : Int, _ front : Int, _ clean : inout Int, _ m : mapInfo, _ visited : inout [[Bool]])
{
var index = front
for _ in 0..<4
{
let (dx,dy) = direction[index]
index -= 1
if index == -1
{
index = 3
}
let (nx,ny) = (x+dx,y+dy)
if nx<0||nx>m.width-1||ny<0||ny>m.height-1
{
continue
}
if m.map[ny][nx] == 0 && !visited[ny][nx]
{
visited[ny][nx] = true
clean += 1
DFS(nx, ny, index, &clean, m, &visited)
}
}
let (backxD,backyD) = backDirect[front]
let (backX,backY) = (x + backxD,y + backyD)
if backX < 0 || backX > m.width-1 || backY < 0 || backY > m.height-1
{
print(clean)
exit(0)
}
if m.map[backY][backX] == 1
{
print(clean)
exit(0)
}
else
{
DFS(backX, backY, front, &clean, m, &visited)
}
}
func BOJ_14503()
{
let m = mapInfo()
var clean = 1
var visited = Array(repeating: Array(repeating: false, count: m.width), count: m.height)
visited[m.start.y][m.start.x] = true
DFS(m.start.x, m.start.y, m.start.direct, &clean, m, &visited)
}
BOJ_14503()
visit my github
'백준 PS일지 > DFS&BFS' 카테고리의 다른 글
[백준/Swift] 2638 : 치즈. 거북이 같은 내 코드 개선시키기... (0) | 2022.07.21 |
---|---|
[백준/Swift] 1726 : 로봇 (0) | 2022.07.18 |
[백준/Swift] 2251 : 물통 (0) | 2022.07.16 |
[백준/Swift] 14442 : 벽 부수고 이동하기 2 (0) | 2022.07.16 |