BOJ_17143_낚시왕

상어의 이동과 낚시 로직을 구현하는 구현 문제
다른 건 다 무난하지만, 상어의 이동을 계산하는 부분이 까다롭다

1초 당 움직일 수 있는 거리가 주어지는데, 만약 그만큼 이동을 하다 벽을 만나면 방향을 전환해서 남은 칸만큼 돌아와야 한다

물론 ==이동할 칸 % 2 x (길이 - 1)==를 한 뒤에 while 문으로 상어를 이동시키며 벽을 확인해도 되지만,
이왕 반복문 안 쓰기로 한 거 계산식으로 풀어보기로 했다

그렇지만 결국 내 머리로 안 돼서 계산으로 푸는 여러 답들을 참고해봤고(집단 지성^^) 내가 이해한 로직은 아래와 같다

상어 이동 로직

  1. 싸이클을 구한다
    상어가 현재 자리에 같은 방향으로 돌아오기 위해서는 2 x (범위 - 1)의 싸이클을 갖는다
    그렇기 때문에 (현재 좌표 + 방향 d x 가는 거리 s)를 싸이클로 나눈 나머지를 구해서 나머지만 가지고 계산하면 된다

  2. 여기서 구한 나머지(편의 상 r이라고 하겠다)는 이제 두 가지 조건에 따라 처리한다

    1. 0 <= r < 범위 라면 r은 좌표와 동일하다. 벽에 부딪히지 않은 상태인 것이다
    2. 범위 <= r < 싸이클 이라면 벽에 부딪혀 방향 전환을 해야한다
      이때, 싸이클 - 현재 거리를 하면 방향 전환 후 도착하는 지점이 나온다

    길이가 5이고, 싸이클이 2 x (5 - 1) = 8의 길이인 경우를 생각해보자
    어떤 값을 싸이클로 나눈 나머지의 범위는 0 <= x < 8이 될 것이다

거리 좌표
0 0
1 1
2 2
3 3
4 4
5 3
6 2
7 1
상어가 벽에 부딪히고, 즉 최대 가능 길이인 5 - 1 = 4에 도달한 후, 다시 1씩 작아지며 이동하는데
이때 이동하는 거리는 (4 + n) 이고 좌표는 ==(4 - n)==로 4를 기준으로 대칭된다.

그렇기 때문에 둘을 더한 값은 싸이클의 길이가 되며
싸이클 - 현재 거리를 하면 1회 방향 전환 후 도달하게 되는 좌표가 나오는 것이다

이를 활용해서 상어를 이동시켜 주면 된다

그러나 나는 수학과가 아니기 때문에 틀렸을 수도 있다 지적 환영~~

R, C, M = list(map(int, input().split()))  
fish_bowl = [[0] * (C) for _ in range(R)]  
shark_dic = {}  
shark_sum = 0  
dx = [0, -1, 1, 0, 0]  
dy = [0, 0, 0, 1, -1]  
  
  
def input_data():  
    # 입력  
    for i in range(M):  
        temp_li = list(map(int, input().split()))  
        temp_li[0] -= 1  
        temp_li[1] -= 1  
  
        shark_dic[i + 1] = temp_li  # x, y, 속력, 이동 방향, 크기  
  
        fish_bowl[temp_li[0]][temp_li[1]] = i + 1  # 상어 표시  
  
  
def print_fish():  
    for i in range(R):  
        for j in range(C):  
            print(fish_bowl[i][j], end=" ")  
        print('')  
    print('')  
  
  
def move_right(i):  
    # 낚시왕의 이동  
    for j in range(R):  
        if fish_bowl[j][i] > 0:  
            shark_info = shark_dic.pop(fish_bowl[j][i])  
            fish_bowl[j][i] = 0  
  
            return shark_info[4]  
  
    return 0  
  
  
def calculate(s, nx, ny, now_d):  
    cycle_x = 2 * (R - 1)  
    cycle_y = 2 * (C - 1)  
  
    if now_d in [3, 4]:  # 좌우 이동  
        ny = (ny + s * dy[now_d]) % cycle_y  
        if ny >= C:  
            ny = cycle_y - ny  
            now_d = 7 - now_d  # 3 <-> 4 방향 전환  
    elif now_d in [1, 2]:  # 상하 이동  
        nx = (nx + s * dx[now_d]) % cycle_x  
        if nx >= R:  
            nx = cycle_x - nx  
            now_d = 3 - now_d  # 1 <-> 2 방향 전환  
  
    return nx, ny, now_d  
  
  
def move_shark():  
    for key in shark_dic.keys():  
        x, y, s, d, z = shark_dic[key]  
  
        next_d = d + 1 if d % 2 == 1 else d - 1  
        length = R if d <= 2 else C  
        nx, ny, direction = calculate(s, x, y, d)  
  
        shark_dic[key] = [nx, ny, s, direction, z]  
  
  
def shark_position():  
    global fish_bowl  
    fish_bowl = [[0] * (C) for _ in range(R)]  
    remove_key = []  
  
    for key in shark_dic.keys():  
        x, y, s, d, z = shark_dic[key]  
  
        if fish_bowl[x][y] == 0:  
            fish_bowl[x][y] = key  
  
        else:  
            rival_shark = shark_dic[fish_bowl[x][y]]  
  
            if rival_shark[4] > z:  
                remove_key.append(key)  
  
            else:  
                remove_key.append(fish_bowl[x][y])  
                fish_bowl[x][y] = key  
  
    for key in remove_key:  
        shark_dic.pop(key)  
  
  
# 실행  
input_data()  
  
if M == 0:  
    print(0)  
  
else:  
    for i in range(0, C):  
        # 낚시  
        shark_sum += move_right(i)  
        # 상어 이동  
        move_shark()  
        # 상어 배치  
        shark_position()  
  
    print(shark_sum)