https://www.acmicpc.net/problem/20056
공부 날짜 : 2022.10.06
정답 참조 여부 : X
마법사가된 상어가 파이어볼을 움직인다. 파이어볼은 속도와 방향을 가지고 움직이며 같은 장소에서 만나면 합쳐진뒤 4개로 나뉘어진다. 4개로 나뉘어지는 조건이 정해져있으며 상어가 k번 파이어볼을 움직인후의 남은 파이어볼의 질량의 합을 묻는 문제이다.
어렵진 않았다.
파이어볼을 규칙에 맞게 움직이고 같은장소에서 만난 파이어볼끼리 합쳐주고 나눠주면되는 아주 간단한 문제.
헷갈렸던 부분은 파이어볼이 합쳐지고 나뉘어지는 부분인데
없어져야 하는 파이어볼은 index로 저장되어 있고 파이어볼이 없어질때마다 index에 변화가 생기기 때문에 해당방식으로 접근하는건 어려웠다.
해결 방법은 파이어볼의 정보에 합쳐져서 없어져야하는 파이어볼인지 판단하는 bool을 추가해주고
마지막에 새로운 리스트에 남아있는 파이어볼만 옮겨준뒤 파이어볼 리스트를 갱신해주는 방식을 사용했다.
실무에서 이런 방식이 옳다고 여겨질지는 모르겠지만 (메모리 효율때문에?) 독학으로 생각하는 내 기준에서 생각할 수 있는 방식은 이게 최선이라 생각한다.
import sys
from copy import deepcopy
input = sys.stdin.readline
######################################################
#데이터 입력받기
n,m,k = map(int, input().split())
fire_ball = []
for _ in range(m):
r,c,m,s,d = map(int, input().split())
#5개의 정보와 합쳐져서 없어져야하는지 여부가 딤긴 리스트
fire_ball.append([r-1,c-1,m,s,d,False])
######################################################
#필요한 기본 정보
dx = [-1,-1,0,1,1,1,0,-1]
dy = [0,1,1,1,0,-1,-1,-1]
######################################################
#파이어볼 이동
def move_fire():
global fire_ball
graph = [[[] for _ in range(n)] for _ in range(n)]
#합쳐지고 나눠줘야하는 위치를 담는 변수
need_setparate = []
#모든 파이어볼에 대해서
for index in range(len(fire_ball)):
x, y, mass, speed, dir, _ = fire_ball[index]
nx = x + (speed * dx[dir])
ny = y + (speed * dy[dir])
#범위 이탈 방지를 위한 나머지 연산
nx %= n
ny %= n
#좌표에 파이어볼의 index를 추가해줌
graph[nx][ny].append(index)
#파이어볼의 위치 갱신
fire_ball[index][0] = nx
fire_ball[index][1] = ny
#분리가 필요한 위치의 좌표를 추가해줌
#2일때만 추가해줘야 3,4,5일때 중복으로 추가되지 않음
if len(graph[nx][ny]) == 2:
need_setparate.append([nx,ny])
#같은 위치에 있는 파이어 볼이 있을때
if len(need_setparate) != 0:
for x,y in need_setparate:
#분리된 후의 질량,속도, 방향을 결정해서 값을 받아옴
mass,speed,dir_bool = fusion_and_setparate(graph[x][y])
#무게가 0이면 패스
if mass == 0:
continue
#받아온 방향에 대해서 방향설정 후 추가
if dir_bool:
for dir in range(0,7,2):
fire_ball.append([x,y,mass,speed,dir,False])
else:
for dir in range(1,8,2):
fire_ball.append([x,y,mass,speed,dir,False])
#합쳐진 파이어볼들 없애주기
new_fire_ball = []
for index in range(len(fire_ball)):
#없어져야하는 값은 넣지않고
if fire_ball[index][5]:
continue
#그 외의 값만 새 리스트에 담아줌
new_fire_ball.append(deepcopy(fire_ball[index]))
#파이어볼 리스트 갱신
fire_ball = deepcopy(new_fire_ball)
######################################################
#파이어볼 합친뒤 나누기
def fusion_and_setparate(same_postion_fire_list):
global fire_ball
mass = 0
speed = 0
count = 0
#True로 반환하면 0,2,4,6
#False로 반환하면 1,3,5,7
dir_bool = True
for index in range(len(same_postion_fire_list)):
#해당 파이어볼은 합쳐졌으므로 다음 연산에서 없어져야됨
fire_ball[same_postion_fire_list[index]][5] = True
mass += fire_ball[same_postion_fire_list[index]][2]
speed += fire_ball[same_postion_fire_list[index]][3]
count += 1
#True를 아직 갖고있고 이전값과 비교해서 홀or짝이 다르면
if dir_bool and fire_ball[same_postion_fire_list[index-1]][4]%2 != fire_ball[same_postion_fire_list[index]][4]%2:
dir_bool = False
mass = mass//5
speed = speed//count
return mass, speed, dir_bool
######################################################
#연산수행
for _ in range(k):
move_fire()
result = 0
for data in fire_ball:
result += data[2]
print(result)