Search
Duplicate
🥇

마법사 상어와 파이어볼

주차
문제번호
20056
언어
Python
티어
골드
유형
구현
nj_Blog
O
nj_상태
완료
이해도
풀이
사람
이해도 2
13 more properties

문제링크

https://www.acmicpc.net/problem/20056

코드 제출 기록 (메모리 및 시간)

제출 날짜

@4/16/2021

메모리

151888 KB

시간

2488 ms

메모

구현은 다소 쉬웠으나 시간초과 때문에 오래 걸린 문제

문제풀이

1. 방향원소

방향이 0~7까지 항상 고정되어 있으므로
dc = [0, 1, 1, 1, 0, -1, -1, -1] dr = [-1, -1, 0, 1, 1, 1, 0, -1]
Python
복사
→ 방향원소의 0, 1, 2, 3, 4, 5, 6, 7 번째 c, r 좌표의 변화를 의미

2. 전반적인 구현 아이디어

3. 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동

파란 식을 사용하여 1 번칸보다 작은 원소에 접근하면 N, N 번 칸보다 큰 원소에 접근하면 1 이 계산되도록 함
def move_marble(N): for arr in marble: _r = arr[0] _c = arr[1] _m = arr[2] _s = arr[3] _d = arr[4] _r = ((_r + dr[_d] * _s) + N) % N _c = ((_c + dc[_d] * _s) + N) % N if _r == 0: _r = N if _c == 0: _c = N arr[0] = _r arr[1] = _c arr[2] = _m arr[3] = _s arr[4] = _d
Python
복사

Code

시간복잡도 무시하고 쌩구현 → 시간초과
# 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동 def move_marble(N): for arr in marble: _r = arr[0] _c = arr[1] _m = arr[2] _s = arr[3] _d = arr[4] _r = ((_r + dr[_d] * _s) + N) % N _c = ((_c + dc[_d] * _s) + N) % N if _r == 0: _r = N if _c == 0: _c = N arr[0] = _r arr[1] = _c arr[2] = _m arr[3] = _s arr[4] = _d if __name__ == '__main__': marble = [] dc = [0, 1, 1, 1, 0, -1, -1, -1] dr = [-1, -1, 0, 1, 1, 1, 0, -1] # N, M, K, marble 입력받기 N, M, K = map(int, input().split()) for i in range(M): arr = list(map(int, input().split())) marble.append(arr) while K > 0: K -= 1 move_marble(N) # marble 배열 row, column 순서로 정렬 marble = sorted(marble, key=lambda x: (x[0], x[1])) ## 같은 칸에 두개 이상의 구슬이 있으면 4개로 쪼개기 for i in range(1, N+1): for j in range(1, N+1): # arr[0] = i, arr[1] = j 인 리스트들을 tmp에 저장 tmp = [] for arr in marble: if (arr[0] == i) and (arr[1] == j): tmp.append(arr) if len(tmp) >= 2: dd = [] sum_m = 0 sum_s = 0 for arr2 in tmp: sum_m += arr2[2] sum_s += arr2[3] if arr2[4] % 2 == 0: dd.append(0) else: dd.append(1) marble.remove(arr2) for k in range(4): if sum_m//5 != 0: if (dd.count(1) == len(tmp)) or (dd.count(0) == len(tmp)): marble.append([tmp[0][0], tmp[0][1], sum_m//5, sum_s//len(tmp), 2*k]) else: marble.append([tmp[0][0], tmp[0][1], sum_m//5, sum_s//len(tmp), 2*k + 1]) ## 질량의 합 구하기 result = 0 for arr in marble: result += arr[2] print(result)
Python
복사
visited 함수를 추가하여 시간 최소화 → but...시간초과
marble = [] # 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동 def move_marble(visited, N): for arr in marble: _r = arr[0] _c = arr[1] _s = arr[3] _d = arr[4] visited[_r][_c].remove(arr) _r = ((_r + dr[_d] * _s) + N) % N _c = ((_c + dc[_d] * _s) + N) % N if _r == 0: _r = N if _c == 0: _c = N arr[0] = _r arr[1] = _c arr[3] = _s arr[4] = _d visited[_r][_c].append(arr) return visited if __name__ == '__main__': marble = [] dc = [0, 1, 1, 1, 0, -1, -1, -1] dr = [-1, -1, 0, 1, 1, 1, 0, -1] # N, M, K, marble 입력받기 N, M, K = map(int, input().split()) visited = [[[] for _ in range(N+1)] for _ in range(N+1)] for i in range(M): arr = list(map(int, input().split())) marble.append(arr) visited[arr[0]][arr[1]].append(arr) while K > 0: K -= 1 visited = move_marble(visited, N) # marble 배열 row, column 순서로 정렬 marble = sorted(marble, key=lambda x: (x[0], x[1])) ## 같은 칸에 두개 이상의 구슬이 있으면 4개로 쪼개기 for i in range(1, N+1): for j in range(1, N+1): if len(visited[i][j]) >= 2: dd = [] sum_m = 0 sum_s = 0 num = len(visited[i][j]) for nn in range(num): arr2 = visited[i][j][0] sum_m += arr2[2] sum_s += arr2[3] if (arr2[4] % 2) == 0: dd.append(0) else: dd.append(1) marble.remove(arr2) visited[i][j].remove(arr2) mm = sum_m//5 ss = sum_s//num if (dd.count(1) == num) or (dd.count(0) == num): for k in range(4): new_arr = [i, j, mm, ss, 2*k] marble.append(new_arr) visited[i][j].append(new_arr) else: for k in range(4): new_arr = [i, j, mm, ss, 2*(k+1) - 1] marble.append(new_arr) visited[i][j].append(new_arr) for arr in marble: if arr[2] == 0: marble.remove(arr) visited[arr[0]][arr[1]].remove(arr) ## 질량의 합 구하기 result = 0 for arr in marble: result += arr[2] print(result)
Python
복사
성공(?)한 코드!
질량이 0인 구슬은 아예 추가를 하지 않도록 수정 (빨간색 부분)
marble = [] # 모든 파이어볼이 자신의 방향 di로 속력 si칸 만큼 이동 def move_marble(visited, N): for arr in marble: _r = arr[0] _c = arr[1] _s = arr[3] _d = arr[4] visited[_r][_c].remove(arr) _r = ((_r + dr[_d] * _s) + N) % N _c = ((_c + dc[_d] * _s) + N) % N if _r == 0: _r = N if _c == 0: _c = N arr[0] = _r arr[1] = _c arr[3] = _s arr[4] = _d visited[_r][_c].append(arr) return visited if __name__ == '__main__': marble = [] dc = [0, 1, 1, 1, 0, -1, -1, -1] dr = [-1, -1, 0, 1, 1, 1, 0, -1] # N, M, K, marble 입력받기 N, M, K = map(int, input().split()) visited = [[[] for _ in range(N+1)] for _ in range(N+1)] for i in range(M): arr = list(map(int, input().split())) marble.append(arr) visited[arr[0]][arr[1]].append(arr) while K > 0: K -= 1 visited = move_marble(visited, N) # marble 배열 row, column 순서로 정렬 marble = sorted(marble, key=lambda x: (x[0], x[1])) ## 같은 칸에 두개 이상의 구슬이 있으면 4개로 쪼개기 for i in range(1, N+1): for j in range(1, N+1): if len(visited[i][j]) >= 2: dd = [] sum_m = 0 sum_s = 0 num = len(visited[i][j]) for nn in range(num): arr2 = visited[i][j][0] sum_m += arr2[2] sum_s += arr2[3] if (arr2[4] % 2) == 0: dd.append(0) else: dd.append(1) marble.remove(arr2) visited[i][j].remove(arr2) mm = sum_m//5 ss = sum_s//num if mm != 0: if (dd.count(1) == num) or (dd.count(0) == num): for k in range(4): new_arr = [i, j, mm, ss, 2*k] marble.append(new_arr) visited[i][j].append(new_arr) else: for k in range(4): new_arr = [i, j, mm, ss, 2*(k+1) - 1] marble.append(new_arr) visited[i][j].append(new_arr) # for arr in marble: # if arr[2] == 0: # marble.remove(arr) # visited[arr[0]][arr[1]].remove(arr) ## 질량의 합 구하기 result = 0 for arr in marble: result += arr[2] print(result)
Python
복사

참고