문제 링크
코드트리 | 코딩테스트 준비를 위한 알고리즘 정석
국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.
www.codetree.ai
풀이
어려웠던 점
1. 최소 정사각형의 좌상단, 우상단 위치 구하기
2. 정사각형 시계 방향 회전
graph : index에 해당하는 칸 별 내구도 저장
players : player들의 위치 저장
1. 참가자 이동
def move(x,y):
# 현재 위치에서 최단 거리
origin = abs(x-s_x) + abs(y-s_y)
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if nx < 0 or nx >= n or ny < 0 or ny >= n :
continue
# 이동했을 때 최단 거리
new = abs(nx-s_x) + abs(ny-s_y)
# 최단 거리 줄어들고
if new < origin :
# 이동할 수 있는 칸이면 이동
if graph[nx][ny] == 0 :
return nx,ny
# 이동할 수 있는 칸이 없는 경우
return -1, -1
2. 최소 정사각형 찾기
square = []
# 최소 정사각형 구하기
for x,y in new_players :
# 정사각형 크기 구하기
s_size = max(abs(x-s_x), abs(y-s_y))
s_r, s_c = -1, -1
# 좌상단, 우상단 위치 구하기
if abs(x-s_x) < abs(y-s_y) :
s_r = max(x,s_x) - abs(y-s_y)
if s_r < 0 :
s_r = 0
s_c = min(y, s_y)
elif abs(x-s_x) == abs(y-s_y) :
s_r = min(x,s_x)
s_c = min(y,s_y)
else :
s_r = min(x,s_x)
s_c = max(y, s_y) - abs(x-s_x)
if s_c < 0 :
s_c = 0
square.append((s_size+1, s_r, s_c))
# 크기 작은 순, r 작은 순, c 작은 순으로 정렬
square.sort()
3. 정사각형 회전 & 출구 회전 & 내구도 -1
회전할 때는 현재 위치에서 좌상단, 우상단 좌표를 빼준 위치에서 회전한다.
그래야 0,0 좌표 기준으로 회전할 수 있게 됨 .
회전 시킨 후 다시 좌상단, 우상단 좌표 더하기
def rotate(data):
global s_x, s_y, n
s = data[0]
s_r = data[1]
s_c = data[2]
# 출구 회전
# 현재 위치에서 좌상단, 우상단 좌표를 빼줌 -> 0,0 기준으로 회전하게 됨
tmp_x = s_x - s_r
tmp_y = s_y - s_c
# 시계 방향 회전
tmp_x, tmp_y = tmp_y, s - tmp_x - 1
# 다시 좌상단, 우상단 좌표 더해줌
tmp_x += s_r
tmp_y += s_c
# 출구 좌표 갱신
s_x = tmp_x
s_y = tmp_y
new_graph = [ [0] * s for _ in range(s)]
for i in range(s_r, s_r + s):
for j in range(s_c, s_c + s):
# 마찬가지로 현재 위치에서 좌상단, 우상단 좌표 빼줌 -> 0,0 기준으로 회전 시키기 위함
x = i - s_r
y = j - s_c
# 회전
x, y = y, s - x - 1
# 0,0 기준으로 회전한 결과 new_graph에 대입
new_graph[x][y] = graph[i][j]
for i in range(s):
for j in range(s):
graph[i+s_r][j+s_c] = new_graph[i][j]
for i in range(s):
for j in range(s):
if graph[i+s_r][j+s_c] :
# 내구도 1 씩 줄어듬
graph[i+s_r][j+s_c] -= 1
4. 정사각형 안에 포함된 플레이어들 회전
s, s_r, s_c = square[0]
rotate_players = []
# 정사각형 안에 포함된 플레이어들 위치 회전
for x,y in new_players:
if s_r <= x < s_r + s and s_c <= y < s_c + s :
# 마찬가지로 0,0 좌표 기준으로 회전하기 위해 좌상단, 우상단 값 빼줌
nx = x - s_r
ny = y - s_c
# 회전
nx, ny = ny, s-nx-1
# 다시 원래 위치로
nx += s_r
ny += s_c
rotate_players.append((nx,ny))
# 정사각형 안에 포함되지 않은 경우 원래 위치
else :
rotate_players.append((x,y))
# 플레이어 위치 갱신
players = rotate_players
전체 코드
from collections import deque
import copy
n, m, k = map(int,input().split())
graph = []
for _ in range(n):
graph.append(list(map(int,input().split())))
players = []
for _ in range(m):
a,b = map(int,input().split())
players.append((a-1,b-1))
s_x, s_y = map(int,input().split())
s_x -= 1
s_y -= 1
dx = [-1,1,0,0]
dy = [0,0,-1,1]
def move(x,y):
# 현재 위치에서 최단 거리
origin = abs(x-s_x) + abs(y-s_y)
# 상하 우선
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if nx < 0 or nx >= n or ny < 0 or ny >= n :
continue
# 이동한 칸에서의 최단거리
new = abs(nx-s_x) + abs(ny-s_y)
# 최단 거리 줄어듬
if new < origin :
# 이동할 수 있는 칸
if graph[nx][ny] == 0 :
return nx,ny
# 이동할 수 없는 경우
return -1, -1
def rotate(data):
global s_x, s_y, n
s = data[0]
s_r = data[1]
s_c = data[2]
# 출구 회전
# 현재 위치에서 좌상단, 우상단 좌표를 빼줌 -> 0,0 기준으로 회전하게 됨
tmp_x = s_x - s_r
tmp_y = s_y - s_c
# 시계 방향 회전
tmp_x, tmp_y = tmp_y, s - tmp_x - 1
# 다시 좌상단, 우상단 좌표 더해줌
tmp_x += s_r
tmp_y += s_c
# 출구 좌표 갱신
s_x = tmp_x
s_y = tmp_y
new_graph = [ [0] * s for _ in range(s)]
for i in range(s_r, s_r + s):
for j in range(s_c, s_c + s):
# 마찬가지로 현재 위치에서 좌상단, 우상단 좌표 빼줌 -> 0,0 기준으로 회전 시키기 위함
x = i - s_r
y = j - s_c
# 회전
x, y = y, s - x - 1
# 0,0 기준으로 회전한 결과 new_graph에 대입
new_graph[x][y] = graph[i][j]
for i in range(s):
for j in range(s):
graph[i+s_r][j+s_c] = new_graph[i][j]
for i in range(s):
for j in range(s):
if graph[i+s_r][j+s_c] :
# 내구도 1 씩 줄어듬
graph[i+s_r][j+s_c] -= 1
ans = 0
for _ in range(k):
new_players = []
for x,y in players:
nx, ny = move(x,y)
# 이동할 수 없는 경우 이동하지 않음
if nx == -1 and ny == -1 :
new_players.append((x,y))
# 출구 도착
elif nx == s_x and ny == s_y :
ans += 1
continue
# 이동
else :
new_players.append((nx,ny))
ans += 1
# 모든 플레이어 탈출
if len(new_players) == 0 :
break
square = []
# 최소 정사각형 구하기
for x,y in new_players :
# 정사각형 크기 구하기
s_size = max(abs(x-s_x), abs(y-s_y))
s_r, s_c = -1, -1
# 좌상단, 우상단 위치 구하기
if abs(x-s_x) < abs(y-s_y) :
s_r = max(x,s_x) - abs(y-s_y)
if s_r < 0 :
s_r = 0
s_c = min(y, s_y)
elif abs(x-s_x) == abs(y-s_y) :
s_r = min(x,s_x)
s_c = min(y,s_y)
else :
s_r = min(x,s_x)
s_c = max(y, s_y) - abs(x-s_x)
if s_c < 0 :
s_c = 0
square.append((s_size+1, s_r, s_c))
# 크기 작은 순, r 작은 순, c 작은 순으로 정렬
square.sort()
# 회전
rotate(square[0])
s, s_r, s_c = square[0]
rotate_players = []
# 정사각형 안에 포함된 플레이어들 위치 회전
for x,y in new_players:
if s_r <= x < s_r + s and s_c <= y < s_c + s :
# 마찬가지로 0,0 좌표 기준으로 회전하기 위해 좌상단, 우상단 값 빼줌
nx = x - s_r
ny = y - s_c
# 회전
nx, ny = ny, s-nx-1
# 다시 원래 위치로
nx += s_r
ny += s_c
rotate_players.append((nx,ny))
# 정사각형 안에 포함되지 않은 경우 원래 위치
else :
rotate_players.append((x,y))
# 플레이어 위치 갱신
players = rotate_players
print(ans)
print(s_x+1, s_y+1)
'개발 > algorithm' 카테고리의 다른 글
[코드트리] 코드트리 채점기 - Python (1) | 2023.10.13 |
---|---|
[코드트리] 토끼와 경주 - Python (0) | 2023.10.13 |
[코드트리] 산타의 선물 공장2 - Python (1) | 2023.10.11 |
[코드트리] 산타의 선물 공장 - Python (1) | 2023.10.11 |
[코드트리] 포탑 부수기 - Python (2) | 2023.10.11 |