본문 바로가기

알고리즘/백준 문제 풀이

[Python] 2758번 로또

728x90

 

https://www.acmicpc.net/problem/2758

 

2758번: 로또

선영이는 매주 엄청난 돈을 로또에 투자한다. 선영이가 하는 로또는 1부터 m까지 숫자 중에 n개의 수를 고르는 로또이다. 이렇게 열심히 로또를 하는데, 아직까지 한 번도 당첨되지 않은 이유는

www.acmicpc.net


 

23/03/13

 

 

전형적인 2차원 DP문제로, 만약 DP가 아니라 백트래킹으로 접근한다면 시간초과가 날 수도 있을 문제이다.


 

문제 접근 방식:

 

 

$\mathrm{DP}$문제를 접근할 때에는 먼저 상태를 정의하는게 우선이다.

 

이 문제에서는 영향을 미치는 요소가 $n$과 $m$ 두가지 라는 사실을 알 수 있다.

 

때문에 다음과 같이 상태를 정의해보자.

 

$\mathrm{DP}[i][j]$ $=$ 선영이가 지금까지 $i$개의 숫자를 골랐을 때, 숫자 $j$를 고르는 경우의 수

 

다음과 같이 상태를 정의한다면, 점화식을 세우는 것은 그리 어렵지는 않다.

 

 

문제에 주어진 바에 따르면, 선영이는 이전의 숫자보다 항상 적어도 2배가 크게끔 다음 숫자를 고른다고 하였다.

 

이를 이용하면, 선영이가 만약 이번에 $j$라는 숫자를 고르려고 한다면, 그 상태는 분명 이전 상태의 숫자보다 $2$배 이상이 되야하므로, 이전 상태의 숫자는 $0$부터 $j//2$까지 가능하다.

 

따라서 점화식은 아래와 같이 세울 수 있다.

 

$$\mathrm{DP}[i][j] = \mathrm{DP}[i-1][0] + ... + \mathrm{DP}[i-1][j//2]$$

 

 

초기 DP의 값($\mathrm{DP}[0][0]$)은 상태를 해석하자면, 아무것도 없는 상태, 한 가지로 해석할 수 있으므로 1이라고 초기화 해준다.

 

이후 숫자 제한 범위인 $n = 10$과 $m = 2000$까지의 $\mathrm{DP}$배열을 선언해주고, 이를 미리 채워줘서 각 쿼리마다 $\sum_{k = 0}^{m} \mathrm{DP}[n][k]$을 반환하면 된다.


아래는 내가 위의 접근 방식과 같이 작성한 파이썬 코드이다. 더보기를 누르면 확인할 수 있다.

더보기
# 2758번 로또
# DP
'''
접근 방법:
DP[i][j] = 선영이가 지금까지 i개의 숫자를 골랐을 때, 숫자 j를 고르는 경우의 수
DP[i][j] = DP[i-1][1] + DP[i-1][2] + ... DP[i-1][j//2]
'''
DP = [[0 for _ in range(2001)] for _ in range(11)]
DP[0][0] = 1
for i in range(1, 11):
    for j in range(1, 2001):
        DP[i][j] = sum(DP[i-1][k] for k in range(j//2+1))
T = int(input())
for _ in range(T):
    n, m = map(int, input().split())
    print(sum(DP[n][k] for k in range(2**(n-1), m+1)))

'알고리즘 > 백준 문제 풀이' 카테고리의 다른 글

[Python] 9066번 금고  (0) 2023.03.21
[Python] 9718번 Matrix Transformation  (0) 2023.03.14
[Python] 1563번 개근상  (0) 2023.03.13
[Python] 1229번 육각수  (0) 2023.03.13
[Python] 2421번 저금통  (0) 2023.03.13