728x90
# 소요시간 - 100분
# 접근 방법
- s 기업 코딩테스트 대비 구현, 시뮬레이션 문제를 풀게 되었다.
- 문제를 읽으면서 주어진 조건을 요약하고 의사 코드로 작성하면서 눈 여겨본 중요한 키포인트는 아래와 같았다.
- 사람들을 주어진 경로로 이동시키기
- 라운드에 따른 공을 던지는 시작점과 방향
- 공을 맞은 사람의 순서와 뒤집기
- 따라서, 각 팀의 사람들의 위치를 기록할 team_loc리스트와 머리의 위치를 기록할 team_head 딕셔너리를 사용해주었다.
- 주어진 배열을 순회하며 1을 만나는 경우 idx를 팀 번호로 사용하여 bfs 함수를 실행시켜 각 팀의 머리 ~ 꼬리 순서로 기록해주었다.
- 이 때, 3을 만난 경우는 따로 temp에 저장해둔 후 마지막에 추가해주었다.
- 2 1 3이나 3 1 2와 같은 경우 3을 만나서 바로 종료해버리는 경우가 있었기 때문에...!
- 이후 move 함수를 실행시켜준다.
- 각 팀의 사람들을 순회하며 옮겨줄건데, 우선 head에 기록되어 있는 머리의 위치를 si, sj에 저장해주고 4방향을 탐색하며 4를 찾아 준다.
- 4를 찾았다면 ni, nj에 저장해주고 team_head와 team_loc, arr의 값을 변경해준다.
- 이제 2번째 사람부터 ni, nj에 현재 위치를 저장하고 si, sj로 이동 후 ni, nj를 4로 변경해준다.
- 마지막의 경우 3 또는 1이 arr에 기록되어 있기 때문에 무조건 3으로 변경해준다.
- 이후, head에 기록된 값으로 다시 arr과 team_loc[team][0]번을 변경해주면 된다.
- 만약 머리와 꼬리에 빈 칸이 없는 경우 3번이 이동 후 1을 4로 변경하기 때문이다..!
- 마지막은 throw함수로 공을 던져준다.
- 여기서 문제를 꼼꼼히 읽지 않아 많은 시간을 소비하였다.
- 2n까지는 0에서 시작하지만, 3~4n은 N-1부터 시작하는 것을 놓쳤다..
- 우선 start => 시작 위치는 n % N으로 구해주고, 방향은 n // N % 4를 통해 구해준다.
- 이후 방향에 따라 시작 위치를 잡아주고 사람을 만난다면 위치를 바로 return
- 못 만난다면 -1, -1을 리턴해준다.
- 사람을 만났다면 team_loc를 순회하며 몇 번째 팀에 있는지 찾아주고, 그 팀에서 몇 번째 순서인지 구한 후 result에 제곱만큼 더해준다.
- 이후, team_loc[팀 번호]를 reverse를 이용해 뒤집어주고, team_head와 arr 값을 변경해주면 된다.
from collections import deque
import sys
sys.stdin = open('input.txt')
def bfs(num):
visited = [[0] * N for _ in range(N)]
bi, bj = team_loc[num][0]
visited[bi][bj] = 1
q = deque()
q.append((bi, bj))
temp = []
while q:
si, sj = q.popleft()
for d in range(4):
ni, nj = si + di[d], sj + dj[d]
if 0<=ni<N and 0<=nj<N and visited[ni][nj] == 0:
if arr[ni][nj] == 2:
q.append((ni, nj))
team_loc[num].append([ni, nj])
visited[ni][nj] = 1
break
elif arr[ni][nj] == 3:
temp.append([ni, nj])
team_loc[num].append(temp[0])
def move():
for idx, t in enumerate(team_loc):
# 머리부터 옮겨주기
si, sj = team_head[idx]
for d in range(4):
ni, nj = si+di[d], sj + dj[d]
if 0<=ni<N and 0<=nj<N and (arr[ni][nj] == 4 or arr[ni][nj] == 3):
arr[ni][nj] = 1
arr[si][sj] = 4
team_head[idx] = [ni, nj]
team_loc[idx][0] = [ni, nj]
break
for m in range(1, len(t)):
ni, nj = team_loc[idx][m]
if arr[ni][nj] == 2:
arr[si][sj] = 2
else:
arr[si][sj] = 3
arr[ni][nj] = 4
team_loc[idx][m] = [si, sj]
si, sj = ni, nj
hi, hj = team_head[idx]
team_loc[idx][0] = [hi, hj]
arr[hi][hj] = 1
def throw(n):
# 시작위치와 방향
start = n % N
d = n // N % 4
if d == 0:
si, sj = start, 0
elif d == 1:
si, sj = N-1,start
elif d == 2:
si, sj = N-1 -start, N-1
else:
si, sj = 0, N-1-start
while 0<=si<N and 0<=sj<N:
if arr[si][sj] in [1, 2, 3]:
return [si, sj]
si += di[d]
sj += dj[d]
return [-1, -1]
N, M, K = map(int, input().split())
arr = [list(map(int, input().split())) for _ in range(N)]
cnt = 0
team_loc = [[] for _ in range(M)]
team_head = dict()
result = 0
di, dj = [0, -1, 0, 1], [1, 0, -1, 0]
# 최초의 팀 기록 해주기
for i in range(N):
for j in range(N):
if arr[i][j] == 1:
team_loc[cnt].append([i, j])
bfs(cnt)
team_head[cnt] = [i, j]
cnt += 1
for k in range(K):
move()
check = throw(k)
if not check == [-1, -1]:
flag = True
for i, c in enumerate(team_loc):
if check in c:
flag = False
for idx, val in enumerate(c):
if check == val:
result += (idx+1) ** 2
break
team_loc[i].reverse()
team_head[i] = team_loc[i][0]
for t in range(len(c)):
ti, tj = team_loc[i][t]
if arr[ti][tj] == 3:
arr[ti][tj] = 1
elif arr[ti][tj] == 1:
arr[ti][tj] = 3
else:
arr[ti][tj] = 2
if not flag:
break
print(result)
- 구현 문제 뿐만 아니라 모든 코드를 짤 때 문제 조건을 꼼꼼히 읽고 의사 코드를 탄탄히 짜는게 중요한 것 같다.
- 또한, 의사 코드를 주석으로 옮기면서 다시 한 번 로직을 짜는 것이 오류를 사전에 방지하는 것을 다시 한번 깨달았따..!
728x90
'ALGORITHM > 정렬, 탐색,구현' 카테고리의 다른 글
[코드트리] 파이썬 - 술래 잡기 (0) | 2023.10.12 |
---|---|
[코드트리] 파이썬 - 나무박멸 (1) | 2023.10.12 |
[코드트리] 파이썬 - 합쳐지는 구슬들 (1) | 2023.10.10 |
[코드트리] 파이썬 - 숫자가 가장 큰 인접한 곳으로 동시에 이동 (1) | 2023.10.10 |
[백준 17142번] 파이썬 - 연구소 3 (0) | 2023.10.09 |