새벽까지

다리 놓기 - 1010

 

1010번: 다리 놓기

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 강의 서쪽과 동쪽에 있는 사이트의 개수 정수 N, M (0 < N ≤ M < 30)이 주어진다.

www.acmicpc.net

성능 요약

메모리: 31256 KB, 시간: 88 ms

분류

조합론, 다이나믹 프로그래밍, 수학

문제 설명

재원이는 한 도시의 시장이 되었다. 이 도시에는 도시를 동쪽과 서쪽으로 나누는 큰 일직선 모양의 강이 흐르고 있다. 하지만 재원이는 다리가 없어서 시민들이 강을 건너는데 큰 불편을 겪고 있음을 알고 다리를 짓기로 결심하였다. 강 주변에서 다리를 짓기에 적합한 곳을 사이트라고 한다. 재원이는 강 주변을 면밀히 조사해 본 결과 강의 서쪽에는 N개의 사이트가 있고 동쪽에는 M개의 사이트가 있다는 것을 알았다. (N ≤ M)

재원이는 서쪽의 사이트와 동쪽의 사이트를 다리로 연결하려고 한다. (이때 한 사이트에는 최대 한 개의 다리만 연결될 수 있다.) 재원이는 다리를 최대한 많이 지으려고 하기 때문에 서쪽의 사이트 개수만큼 (N개) 다리를 지으려고 한다. 다리끼리는 서로 겹쳐질 수 없다고 할 때 다리를 지을 수 있는 경우의 수를 구하는 프로그램을 작성하라.

입력

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 강의 서쪽과 동쪽에 있는 사이트의 개수 정수 N, M (0 < N ≤ M < 30)이 주어진다.

출력

각 테스트 케이스에 대해 주어진 조건하에 다리를 지을 수 있는 경우의 수를 출력한다.


문제 풀이

먼저 이 문제는 여러가지로 순열인 팩토리얼로 문제를 풀 수 있지만, 팩토리얼을 사용하는 것 보다, dp를 이용하는 것이 더 빠르다고 생각하여, 다이나믹 프로그래밍에서 Bottom-Up 방식으로 문제를 풀었습니다.

 

 

아래 글은 다이나믹 프로그래밍 Bottom-up에 대해 설명한 글입입니다.

 

한 번으로 코딩 역량을 향상하는 동적프로그래밍 기법을 알아보자! 🔥

동적프로그래밍은 처음 들어보는 사람들에게는 어려울 수 있지만, 실제로 코드를 작성해보면 그리 어렵지 않습니다. 아래 예제는 대표적인 동적프로그래밍 문제 중 하나인 피보나치 수열을 살

night-knight.tistory.com

참조

 

 

n m 1 2 3 4 5 6 7
1 1 2 3 4 5 6 7
2 x 1 3 6 10 15 21
3 x x 1 4 10 20 35
4 x x x 1 5 15 35
5 x x x x 1 6 21

표의 규칙성을 보면 (2,3) = (1,2) + (2+2) 

 

 

점화식으로는 (i,j) = (i-1,j-1) + (i,j-1)

 

 

 

점화식를 바탕으로 DP  bottom-up 을 사용하여 풀이

 

1. 초기화하기

 dp = [[1]*(m+1) for _ in range(m+1)] # dp 리스트를 m만큼 생성한다. 그리고 모든 수를 1로 만든다.

모든 수를 1로 만드는 이유는 dp의 행렬 같다면 1이기 때문에 먼저 삽입하였습니다.

 

 

파이썬 이중 배열 선언 초기화 컴프리헨션

🤔 이중배열 컴프리헨션이란? 이중배열 컴프리헨션(Double List Comprehension)은 중첩된 리스트를 생성하는 방법 중 하나입니다. 🤯 이중배열 컴프리헨션의 기본 구조 [[expression] for element in iterable if

night-knight.tistory.com

참조

 

 

2. n이 1 이라면 경우의 수는 m

    for i in range(2,m+1):
        dp[1][i]=i

 

 

3. 점화식을 활용한 dp배열 삽입

    for i in range(2,n+1):
        for j in range(i+1,m+1):
            dp[i][j] = dp[i-1][j-1] + dp[i][j-1]

위 표의 규칙성을 이용한 점화식을 사용

 

 

 

전체 코드

def dp_b (n,m) :
    dp = [[1]*(m+1) for _ in range(m+1)]
    for i in range(2,m+1):
        dp[1][i]=i
    for i in range(2,n+1):
        for j in range(i+1,m+1):
            dp[i][j] = dp[i-1][j-1] + dp[i][j-1]
    return dp[n][m]

for _ in range(int(input())):
    west, east =  map(int, input().split())
    print(dp_b(west,east))

 


 

GitHub - SeokJuGo/Studing_CodingTest: CodingTestPractice

CodingTestPractice. Contribute to SeokJuGo/Studing_CodingTest development by creating an account on GitHub.

github.com

 

profile

새벽까지

@GoS

좋아요❤️ 구독👍🏻 감사합니다!