강 서쪽에서 동쪽으로 이어진 다리가 서로 겹쳐지지않게 놓을 수 있는 경우의 수를 구하여라
문제 분석을 위해 주어진 예시를 보며 다리를 놓을 수 있는 경우의 수를 하나씩 세보았다. 강의 서쪽에서 동쪽으로 하나씩 선택하면 경우의 수가 바뀌게 되고 주어진 입축력 예시에서 서쪽 13개 동쪽 29개에서 경우의 수가 엄청나게 많은 걸 봤을때 완전탐색으로 하나씩 세면서 경우의 수를 구하게 되면 불리하다는 생각이 들었다. 수학적 귀납법에 착안해 서쪽과 동쪽에 지점을 하나에서 하나씩 늘려가면서 생각해보니 dp(동적계획법)을 활용하는 문제라는 점을 알았다.
위의 그림은 dp 테이블을 나름 정리한 것이다.
행과 열의 인덱스는 동쪽과 서쪽의 point의 갯수를 의미하고 i -> i의 경우의 수는 1개 고정 1행의 i열은 i개 고정이란 점을 바탕으로 dp테이블을 초기화 하였고, 서쪽과 동쪽의 point를 한 개씩 늘려가며 이전 상태가 다음 상태의 부분집합으로써 가지는 규칙으로 점화식을 세웠다.
코드는 다음과 같다.
tc = int(input())
for _ in range(tc):
n, m = map(int, input().split())
dp = [[0] * (m + 1) for i in range(m + 1)]
for i in range(1, m + 1):
dp[i][i] = 1
dp[1][i] = i
for i in range(2, m + 1):
for j in range(i + 1, m + 1):
dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1]
print(dp[n][m]) # n개의 서쪽에서 m개의 동쪽으로의 경우의 수