알고리즘/Team Notes

최적화 - 3중 for문을 쓰지 않기 위해 나온 테크닉, flattening the state space

everything_is_mine 2025. 6. 9. 11:23

2025년 상반기 오전 2번 문제 개구리의 여행 문제를 풀다 보니 계속 시간초과가 나는 문제가 발생했다.

이러한 시간문제에 맞닥뜨리게 되니 자연스레 최적화에 관심이 갔다.

 

최적화의 방법 중 중첩 for문을 최대한 줄이는 방법이 하나 있더라.

 

원래

1. row

2. col

3. jumpPower

 

위 세 변수에 대해 각각 for문을 돌며 3차원 행렬을 관리해야 한다. 근데 Dijkstra 알고리즘의 경우 노드라는 하나의 값에 대한 최단 거리를 계산하다 보니 이러한 하나의 state 값으로 만들어 줄 수 있다고 한다.

 

그래서 다음과 같이 인덱스를 "펴는" 걸 생각하게 된다.

  • 2D 배열을 1D로 변환할 때 row * width + col  같은 걸 사용한다.
  • 거기에 추가적인 차원이 더 필요하다면 곱해주는 계수를 하나 더 추가한다.

그렇다면 2D 좌표를 1D로 바꿀 때 다른 행렬 인덱스인데 같은 값이 나오는 경우는 없는 것이 확실한가?

 

=> 절대! NEVER!!! 안 나온다.

이를 수식으로 증명하면 다음과 같다.

(row - 1) * gridSize + (col - 1)

(row - 1) * 한 줄에 들어가는 칸 수 + (col - 1) # 행 우선으로 번호를 매기는 방식

 

예시

gridSize = 4 # 예시

row=1, col=1 #→ (1-1)*4 + (1-1) = 0
row=1, col=2 #→ (1-1)*4 + (2-1) = 1
row=1, col=3 #→ (1-1)*4 + (3-1) = 2
row=1, col=4 #→ (1-1)*4 + (4-1) = 3

row=2, col=1 #→ (2-1)*4 + (1-1) = 4
row=2, col=2 #→ (2-1)*4 + (2-1) = 5
row=2, col=3 #→ (2-1)*4 + (3-1) = 6
row=2, col=4 #→ (2-1)*4 + (4-1) = 7


row r, col c → 인덱스 = (r-1) * gridSize + (c-1)

...

이렇게 절대 다른 (row, col) 쌍에서는 같은 값이 안나온다.

왜냐하면,

  • row 가 바뀌면 (row - 1) * gridSize 항이 달라지므로 전체 값이 girdSize 단위로 차이가 생긴다.
  • col 안에서는 row가 고정되어 있을 때 0 ~ (gridSize -1) 범위의 값만 추가가 된다. -> 고로 충돌 안한다.

수식으로 안정성 보장

  • 총 인덱스 공간 : 0 ~ (gridSize * girdSize -1)
  • 각 (row, col) 마다 유일한 번호를 가지게 된다.

 

세번째 차원이 포함 될때도 마찬가지

getStateId = MAX_JUMP_POWER * ((row - 1) * gridSize + (col - 1)) + (jumpPower - 1)

 

  • (row, col) 쌍마다 MAX_JUMP_POWER 개의 jumpPower 상태를 안전하게 구분 할 수 있다
  • 다른 (row, col) 쌍끼리는 MAX_JUMP_POWER 단위로 건너뛰기 때문에 절대 겹칩일이 없다.