문제링크
코드트리 | 코딩테스트 준비를 위한 알고리즘 정석
국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.
www.codetree.ai
풀이
구현 문제로, 산타가 있는 위치로 밀려났을 때 연쇄적으로 밀려다도록 하는 부분은 재귀 함수 사용해서 풀었다.
필요한 변수들은 다음과 같다.
n, m, p, c, d = map(int,input().split())
r_x, r_y = map(int,input().split())
r_x -=1
r_y -=1
# index에 해당하는 산타의 위치 저장
santa = [ [] for _ in range(p+1) ]
# 위치별 산타 번호 저장
graph = [ [0] * n for _ in range(n) ]
# index에 해당하는 산타의 점수 저장
scores = [0] * (p+1)
# index에 해당하는 산타 존재 여부 저장
out = [False] * (p+1)
# index에 해당하는 산타가 언제까지 기절하는지 시간 저장
stop_time = [0] * (p+1)
# 몇 초가 흘렸는지
t = 1
for _ in range(p):
i, a, b = map(int,input().split())
a -= 1
b -= 1
santa[i] = [a,b]
graph[a][b] = i
연쇄적으로 밀어내는 함수는 다음과 같다.
# 산타 번호, 산타가 이동할 위치, 이동한 방향
def shoot(s_id, x, y, direct):
# 밀어내진 위치가 범위를 벗어나면 out
if x < 0 or x >= n or y < 0 or y >= n:
out[s_id] = True
return
# 밀어난 위치에도 산타가 있으면 재귀적으로 밀어낸다
if graph[x][y] :
tmp_id = graph[x][y]
# 착지
graph[x][y] = s_id
santa[s_id] = [x,y]
# 연쇄적으로 밀어냄
shoot(tmp_id, x+dx[direct], y+dy[direct], direct)
# 밀어난 위치가 빈 칸이라면 바로 착지
else :
graph[x][y] = s_id
santa[s_id] = [x,y]
1. 루돌프 이동 함수
# 상하좌우대각선 8방향
dx = [-1,0,1,0,1,1,-1,-1]
dy = [0,1,0,-1,1,-1,1,-1]
def move_rudolf():
global r_x, r_y
# 산타 별 거리 구하기
route = []
for i in range(1,p+1):
if out[i]:
continue
s_x, s_y = santa[i]
dist = (s_x-r_x)**2 + (s_y-r_y)**2
# 거리 작은 순 -> r 큰 순 -> c 큰 순으로 정렬
route.append([dist, -s_x, -s_y, i])
route.sort()
# 거리, 돌진할 산타 위치, 돌진한 산타 번호
dist, x, y, i = route[0]
x = -x
y = -y
tmp_route = []
# 돌진할 산타와 거리가 가까워지는 방향 찾기
for i in range(8):
nx = r_x + dx[i]
ny = r_y + dy[i]
new_dist = (nx-x)**2 + (ny-y)**2
if nx < 0 or nx >=n or ny < 0 or ny >= n :
continue
if new_dist < dist :
tmp_route.append((new_dist, i, nx, ny))
tmp_route.sort()
# 거리, 이동 방향, 이동 후 위치
dist, direct, x, y = tmp_route[0]
# 루돌프 위치 갱신
r_x = x
r_y = y
# 루돌프가 이동한 위치에 산타가 있으면 밀어낸다
if graph[r_x][r_y]:
p_id = graph[r_x][r_y]
# 밀어낸 위치
nx = r_x + dx[direct] * c
ny = r_y + dy[direct] * c
# 밀어내기
graph[r_x][r_y] = 0
# 기절 시간 갱신
stop_time[p_id] = t + 1
# 점수 더하기
scores[p_id] += c
shoot(p_id, nx, ny, direct)
2. 산타 이동 함수
s_dx = [-1,0,1,0]
s_dy = [0,1,0,-1]
def move_santa():
global r_x, r_y
for i in range(1,p+1):
# 범위에 없는 산타
if out[i] :
continue
# 기절한 산타
if stop_time[i] >= t :
continue
x, y = santa[i]
route = []
next_x = x
next_y = y
p_d = -1
# 루돌프와 가까워지는 방향 구하기
for j in range(4):
nx = x + s_dx[j]
ny = y + s_dy[j]
origin = (x-r_x)**2 + (y-r_y)**2
if nx <0 or nx >= n or ny < 0 or ny >= n :
continue
# 이미 산타가 있으면 이동할 수 없음
if graph[nx][ny] :
continue
new_dist = (nx-r_x)**2 + (ny-r_y)**2
if new_dist < origin :
route.append((new_dist, j, nx, ny))
# 가까워지는 방향으로 갈 수 없음 -> 움직이지 않음
if len(route) == 0 :
continue
route.sort()
# 거리, 이동한 방향, 이동한 위치
dist, p_d, next_x, next_y = route[0]
# 이동한 위치에 루돌프가 있으면
if r_x == next_x and r_y == next_y :
# 이동한 방향과 반대방향으로 밀어남
p_d = (p_d+2)%4
nx = r_x + s_dx[p_d] * d
ny = r_y + s_dy[p_d] * d
# 밀어내기
graph[x][y] = 0
# 점수 더하기
scores[i] += d
# 기절 시간 갱신
stop_time[i] = t + 1
shoot(i, nx, ny, p_d)
# 빈칸이면 바로 이동
else :
graph[x][y] = 0
graph[next_x][next_y] = i
santa[i] = [next_x,next_y]
3. 매 턴 이후 점수 더하는 함수
def get_point():
cnt = 0
for i in range(1,p+1):
# 범위에 없는 산타
if out[i]:
continue
# 점수 더하기
scores[i] += 1
cnt += 1
return cnt
전체 코드는 아래와 같다.
n, m, p, c, d = map(int,input().split())
r_x, r_y = map(int,input().split())
r_x -=1
r_y -=1
# index에 해당하는 산타의 위치 저장
santa = [ [] for _ in range(p+1) ]
# 위치별 산타 번호 저장
graph = [ [0] * n for _ in range(n) ]
# index에 해당하는 산타의 점수 저장
scores = [0] * (p+1)
# index에 해당하는 산타 존재 여부 저장
out = [False] * (p+1)
# index에 해당하는 산타가 언제까지 기절하는지 시간 저장
stop_time = [0] * (p+1)
# 몇 초가 흘렸는지
t = 1
for _ in range(p):
i, a, b = map(int,input().split())
a -= 1
b -= 1
santa[i] = [a,b]
graph[a][b] = i
# 상하좌우대각선 8방향
dx = [-1,0,1,0,1,1,-1,-1]
dy = [0,1,0,-1,1,-1,1,-1]
# 산타 번호, 산타 위치, 방향
def shoot(s_id, x, y, direct):
# 밀어내진 위치가 범위를 벗어나면 out
if x < 0 or x >= n or y < 0 or y >= n:
out[s_id] = True
return
# 밀어난 위치에도 산타가 있으면 재귀적으로 밀어낸다
if graph[x][y] :
tmp_id = graph[x][y]
# 착지
graph[x][y] = s_id
santa[s_id] = [x,y]
# 연쇄적으로 밀어냄
shoot(tmp_id, x+dx[direct], y+dy[direct], direct)
# 밀어난 위치가 빈 칸이라면 바로 착지
else :
graph[x][y] = s_id
santa[s_id] = [x,y]
def move_rudolf():
global r_x, r_y
# 산타 별 거리 구하기
route = []
for i in range(1,p+1):
if out[i]:
continue
s_x, s_y = santa[i]
dist = (s_x-r_x)**2 + (s_y-r_y)**2
# 거리 작은 순 -> r 큰 순 -> c 큰 순으로 정렬
route.append([dist, -s_x, -s_y, i])
route.sort()
# 거리, 돌진할 산타 위치, 돌진한 산타 번호
dist, x, y, i = route[0]
x = -x
y = -y
tmp_route = []
# 돌진할 산타와 거리가 가까워지는 방향 찾기
for i in range(8):
nx = r_x + dx[i]
ny = r_y + dy[i]
new_dist = (nx-x)**2 + (ny-y)**2
if nx < 0 or nx >=n or ny < 0 or ny >= n :
continue
if new_dist < dist :
tmp_route.append((new_dist, i, nx, ny))
tmp_route.sort()
# 거리, 이동 방향, 이동 후 위치
dist, direct, x, y = tmp_route[0]
# 루돌프 위치 갱신
r_x = x
r_y = y
# 루돌프가 이동한 위치에 산타가 있으면 밀어낸다
if graph[r_x][r_y]:
p_id = graph[r_x][r_y]
# 밀어낸 위치
nx = r_x + dx[direct] * c
ny = r_y + dy[direct] * c
# 밀어내기
graph[r_x][r_y] = 0
# 기절 시간 갱신
stop_time[p_id] = t + 1
# 점수 더하기
scores[p_id] += c
shoot(p_id, nx, ny, direct)
s_dx = [-1,0,1,0]
s_dy = [0,1,0,-1]
def move_santa():
global r_x, r_y
for i in range(1,p+1):
# 범위에 없는 산타
if out[i] :
continue
# 기절한 산타
if stop_time[i] >= t :
continue
x, y = santa[i]
route = []
next_x = x
next_y = y
p_d = -1
# 루돌프와 가까워지는 방향 구하기
for j in range(4):
nx = x + s_dx[j]
ny = y + s_dy[j]
origin = (x-r_x)**2 + (y-r_y)**2
if nx <0 or nx >= n or ny < 0 or ny >= n :
continue
# 이미 산타가 있으면 이동할 수 없음
if graph[nx][ny] :
continue
new_dist = (nx-r_x)**2 + (ny-r_y)**2
if new_dist < origin :
route.append((new_dist, j, nx, ny))
# 가까워지는 방향으로 갈 수 없음 -> 움직이지 않음
if len(route) == 0 :
continue
route.sort()
# 거리, 이동한 방향, 이동한 위치
dist, p_d, next_x, next_y = route[0]
# 이동한 위치에 루돌프가 있으면
if r_x == next_x and r_y == next_y :
# 이동한 방향과 반대방향으로 밀어남
p_d = (p_d+2)%4
nx = r_x + s_dx[p_d] * d
ny = r_y + s_dy[p_d] * d
# 밀어내기
graph[x][y] = 0
# 점수 더하기
scores[i] += d
# 기절 시간 갱신
stop_time[i] = t + 1
shoot(i, nx, ny, p_d)
# 빈칸이면 바로 이동
else :
graph[x][y] = 0
graph[next_x][next_y] = i
santa[i] = [next_x,next_y]
def get_point():
cnt = 0
for i in range(1,p+1):
# 범위에 없는 산타
if out[i]:
continue
# 점수 더하기
scores[i] += 1
cnt += 1
return cnt
# for debug
def print_graph():
global r_x, r_y
for i in graph:
print(i)
print(santa)
print(out)
print(scores)
print(r_x, r_y)
#print_graph()
while t <= m :
move_rudolf()
#print_graph()
move_santa()
#print_graph()
cnt = get_point()
#print_graph()
# 범위에 존재하는 산타가 없으면 바로 종료
if cnt == 0 :
break
t += 1
#print('---------------')
print(*scores[1:])
'개발 > algorithm' 카테고리의 다른 글
[코드트리] 코드트리 오마카세 - Python (0) | 2023.10.17 |
---|---|
[코드트리] 코드트리 채점기 - Python (1) | 2023.10.13 |
[코드트리] 토끼와 경주 - Python (0) | 2023.10.13 |
[코드트리] 메이즈 러너 - Python (0) | 2023.10.12 |
[코드트리] 산타의 선물 공장2 - Python (1) | 2023.10.11 |