반응형
https://www.codetree.ai/ko/frequent-problems/samsung-sw/problems/ai-robot/description
코딩테스트 기출 문제 설명: AI 로봇청소기 | 코드트리
코딩테스트 기출 문제 AI 로봇청소기의 상세 설명입니다. 문제 요구사항을 정확히 파악하고 효율적인 알고리즘을 설계해보세요.
www.codetree.ai
from collections import deque
ROBOT_DIRECTION = [[-1, 0], [0, -1], [0, 1], [1, 0]] # 상좌우하
def robots_move(robots : deque[list[int]], idx: int) :
"""
robots : 로봇 청소기들 좌표
idx : 현재 로봇 청소기 번호
1. 청소기 이동
이동 거리가 가장 가까운 오염된 격자로 이동. => 가장 가까운 이동거리를 구해야함. BFS
물건이나 청소기가 있는 격자로는 이동불가.
상하좌우로 인접한 격자를 한 칸씩 이동하여 도달하는 데 필요한 최소 이동 횟수를 의미
우선순위 : 가장 가까운 먼지 > 행번호 > 열번호
"""
robot_q = deque()
visited = [[0] * N for _ in range(N)]
# 각 로봇의 좌표를 담아서 이동. 만약 움직였는데 자기의 범위에 먼지가 없으면 -1, -1 로 보낼까?
movement = N*N+1
res_robot = []
for robot in robots :
visited[robot[0]][robot[1]] = 1
robot_q.append([0] + robots[idx]) # 이렇게 되면 [이동횟수, 행, 열] 이 되니까.
while robot_q :
move_cnt, rr, rc = robot_q.popleft()
# 정답처리 : 먼지를 발견했다. 더 짧은 이동거리로.
if maps[rr][rc] > 0 and movement >= move_cnt:
movement = move_cnt
res_robot.append([rr, rc])
for dr, dc in ROBOT_DIRECTION :
nr, nc = rr + dr, rc + dc
# 네방향, 범위내, 미방문, 조건(박스가 있거나, 먼지 발견)
if 0 <= nr < N and 0 <= nc < N and visited[nr][nc] != 1:
# if maps[nr][nc] == -1 :
# continue
if maps[nr][nc] >= 0 :
robot_q.append([move_cnt + 1, nr, nc])
visited[nr][nc] = 1
if len(res_robot) == 0 :
return robots[idx]
else :
res_robot.sort()
return res_robot[0]
if __name__ == "__main__" :
N, K, L = map(int, input().split()) # 격자 크기, 청소기 개수, 테스트 횟수
maps = [list(map(int, input().split())) for _ in range(N)]
robots = deque()
for _ in range(K) :
a, b = map(int, input().split()) # 격자 구조가 1, 1 ~ N, N 이라 -1 씩 해줌
robots.append([a-1, b-1])
# 테스트 결과만큼 돌리라 했으니까.
for _ in range(L) :
# 1. 로봇 청소기 이동
for k in range(K) :
moved_robots = robots_move(robots, k)
robots[k] = moved_robots
# 2. 청소
for k in range(K) :
clean_direction = [
[[0, 0], [-1, 0], [0, 1], [1, 0]], # 오른쪽
[[0, 0], [0, 1], [1, 0], [0, -1]], # 아래쪽
[[0, 0], [1, 0], [0, -1], [-1, 0]], # 왼쪽
[[0, 0], [0, -1], [-1, 0], [0, 1]] # 위쪽
]
dust_amount = []
for idx_direction in range(len(clean_direction)) :
dust_cnt = 0
for cr, cc in clean_direction[idx_direction] :
nr, nc = robots[k][0] + cr, robots[k][1] + cc
if 0 <= nr < N and 0 <= nc < N and maps[nr][nc] != -1 :
dust_cnt += min(20, maps[nr][nc])
dust_amount.append([dust_cnt, idx_direction])
dust_amount.sort(key=lambda x: (-x[0], x[1]))
# 격자마다 청소 할 수 있는 최대 먼지량은 20 이라는 말은 각 격자마다 이겠지?
# dust_amount[robot_idx][0] 을 가져오면 [먼지량, idx_direction]
# 그럼 또 nr, nc 부여해서 max(0, maps[nr][nc] - 20) 하면 되겠네.
dust_direction = dust_amount[0][1]
for cr, cc in clean_direction[dust_direction] :
nr, nc = robots[k][0] + cr, robots[k][1] + cc
if 0 <= nr < N and 0 <= nc < N and maps[nr][nc] != -1 :
maps[nr][nc] = max(0, maps[nr][nc] - 20)
# 3. 먼지 축적
for i in range(N) :
for j in range(N) :
if maps[i][j] > 0 :
maps[i][j] += 5
temp = [[0] * N for _ in range(N)]
# 4. 먼지 확산
for i in range(N) :
for j in range(N) :
if maps[i][j] == 0 :
dust_0 = 0
for di, dj in ROBOT_DIRECTION :
ni, nj = i + di, j + dj
if 0 <= ni < N and 0 <= nj < N and maps[ni][nj] > 0 :
dust_0 += maps[ni][nj]
temp[i][j] = (dust_0 // 10)
for i in range(N) :
for j in range(N) :
if temp[i][j] > 0 :
maps[i][j] += temp[i][j]
# 5. 출력
cnt = 0
for i in range(N) :
for j in range(N) :
if maps[i][j] > 0 :
cnt += maps[i][j]
print(cnt)
if cnt == 0 :
break
드디어 혼자 힘으로 풀었다... 오예
확실히 BFS, DFS 의 개념을 꽉 잡아 놓으니까 이런문제 만나면 자신감이 조금 더 붙는 거 같다.
일요일 스터디에서 가볍게 문제의 키포인트들을 확인하는 시간을 가졌지만, 월요일부터 투자했던 시간이 화요일인 지금 그렇게 아깝지 않게 되었다.
키 포인트들을 하나씩 잡고 가자.
- robots_move :
- 이동횟수, 행 번호, 열 번호를 체크하는 큐가 필요하다.
- 우선순위대로 나열할 수 있어야 한다. 이 방법을 # 정답처리 부분에 해당한다.
- 마지막 행, 열 우열순위는 sort()를 통하여 행이 작으면, 그 다음 열이 작으면이 자동으로 나열된다.
- return 부분도 만약 먼지를 발견하지 못하면 제자리, 아니면 sort 후 가장 앞에 있는 좌표 반환
- res_robot안에 여러 개가 저장되었다는건 같은 반경 안에 여러 개의 먼지가 존재한다는 것이다.
- 청소
- 위치 순서를 잘 기억하자. 오른쪽, 아래쪽, 왼쪽, 위쪽이다. 이러면 idx=[0,1,2,3] 이 된다.
- 해당 로봇의 좌표는 로봇 번호 k로 받아와서 robots[k][n] 으로 처리하면 된다.
- 방향 정렬 순서는 청소 가능한 먼지량이 제일 많은거, idx 순이다. sort(-(청소량), idx)
- 가장 적합한 방향은 [0][1]에 저장되어 있으니까 이렇게 꺼내면 될 것이다.
- 그다음 각 격자마자 최소 0이 되도록 코드 작성
- 먼지 축적
- 이건 그냥 이중 for문 돌리면 된다.
- 먼지 확산
- 처음에는 deepcopy를 활용했었는데 새로운 2차원 배열을 하나 생성하고 확산될 수 있는 공간에 + dust//10 을 하자
- 그리고 maps에다가 추가하면 끝.
- 출력
- 덧셈이야 이중 for문 돌리면 되고, 마지막 전체 먼지량이 0이 되었을 때 끝내는 방법을 생각하지 않았는데, 이 역시 참고해서 풀었다. 생각보다 많이 틀리는데? 허허...
코데풀, 우리 스터디장님 코드 참고
- 2. 청소 단계에서 dust_cnt += min(20, maps[i][j]) 단계를 처음에는 maps[i][j]로 했었다.
- robots_move 함수 부분은 문제가 하도 안풀려서 참고 했는데, 이렇게도 되지 않을까? 생각해서 몇가지를 바꿨다.
- movement > move_cnt => movement >= move_cnt 로 등호를 추가해주었다.
- 마지막 return 부분은 저런식으로 표현해야하는구나 라는걸 느낄 수 있었다.
- movement 코드를 왜 저렇게 짰냐고 물어보신다면, 사실 가장 짧게 이동한 좌표만 들어오고 나머지는 다 탈락될거라는 계산하에 작성을 하였다.
- 코데풀님 코드에서 조금 변경했으면 좋겠는점.
- direction 설정을 for문 안에서 할 것이 아니라 전역 변수로 선언하면 초기화, 갱신을 덜 하게 될테니 조금 더 효율적이지 않을까?
- 내 코드 중에서도 clean_direction 도 마찬가지지만 나중에 따로 만들어서 동작시켜보고 시간, 공간 소모를 한 번 같이 체크해볼 수 있는 시간을 가졌으면 좋겠다.
- 아 나 ROBOT_DIRECTION을 그냥 DIRECTION으로 바꿔야겠다. 먼지 확산에도 같이 썼구나...
CodeTreeTest/samsung-sw/AI 로봇청소기/ai-robot.py at main · jeongminllee/CodeTreeTest
Contribute to jeongminllee/CodeTreeTest development by creating an account on GitHub.
github.com
반응형
'알고리즘 스터디' 카테고리의 다른 글
| [코드트리/파이썬] 해적 선장 코디 (0) | 2026.05.31 |
|---|---|
| [코드트리/파이썬] AI 로봇 청소기 - 3 (0) | 2026.05.15 |
| [코드트리/파이썬] AI 로봇청소기 - 1 (0) | 2026.05.04 |
| [코드트리/파이썬] 가로등 설치 - 2 (0) | 2026.05.03 |
| [코드트리/파이썬] 가로등 설치 (1) | 2026.04.26 |