m면체 주사위 n개를 굴려서 나올 수 있는 경우의 수를 구하는 방법
3886번: Expected Allowance (acmicpc.net)
m면체 주사위 n개를 굴려서 나온 숫자의 합에 컷백 k를 뺀 값만큼 지폐를 받는다고 할 때, 받을 수 있는 지폐 수의 기댓값
이때, k 이하의 수가 나온다면 최소 1장은 받는다
예를 들어 6면체 주사위 2개를 굴리면? 가능한 숫자의 합은 1부터 12까지인데 모든 경우의 수는 36가지이고
숫자의 합이 2인 경우의 수는 (1,1)로 1가지
3인 경우의 수는 (1,2), (2,1)로 2가지
4인 경우의 수는 (1,3), (2,2), (3,1)로 3가지
k = 3이면 지폐를 1가지 받는 경우의 수는 숫자의 합이 2, 3, 4 3가지 경우에 가능하다.
따라서 지폐 1가지 받는 경우의 수는 1+2+3 = 6가지
그러면 먼저 m면체 주사위 n개를 굴려서 나올 수 있는 숫자의 합의 모든 경우의 수를 구해야한다
n개의 자리에 1부터 m까지 아무 숫자나 하나씩 써 넣으면 된다
dp[i][j] = i번째 자리까지 봤을때, 숫자의 합이 j인 경우의 수
i = 0,1,2,3,..,n-1까지 가능하고, n개의 자리 각각에 1부터 m까지 들어갈 수 있으므로 총 합은 mn이다.
0번째 자리에는 1부터 m까지 나올 수 있으므로 i = 1,2,..,m에 대하여 dp[0][i] = 1
i = 1번부터 n번자리까지는 각 자리에 j = 1,2,3,..,m중 하나를 쓸 수 있고, 현재 숫자의 합이 k이면...
dp[i][k] += dp[i-1][k-j]
dp = [[0]*(m*n+1) for _ in range(n)]
for j in range(1,m+1):
dp[0][j] = 1
for i in range(1,n):
for j in range(1,m+1):
for k in range(m*n,-1,-1):
if k >= j:
dp[i][k] += dp[i-1][k-j]
이렇게 하면 dp[n-1]에는 m면체 주사위 n개를 굴려서 나올 수 있는 숫자의 합의 경우의 수가 계산되어 있다
따라서 컷백 k이하의 수의 경우에는 지폐 1장을 받을 수 있고, k보다 큰 수에 대해서는 p - k개만큼 지폐를 받으므로
일단 가능한 모든 경우의 수를 전부 더해놓은 다음, 마지막에 모든 가능한 경우의 수 m**n으로 나눠야 float error가 최소화된다
c = 0
for p in range(n,m*n+1):
if p <= x:
c += (dp[n-1][p])
else:
c += (dp[n-1][p]*(p-x))
print(c/(m**n))
'조합론' 카테고리의 다른 글
여사건을 이용한 경우의 수1 - 특정 수를 포함하는 부분집합 구하는 법 (0) | 2024.08.23 |
---|---|
경기장 일렬 좌석에 앉을 때 사람을 지나치지 않고 전부 앉는 방법의 수 (0) | 2024.07.26 |
다항식의 곱으로 구하는 복수순열1 - 주어진 개수의 알파벳들만으로 만들 수 있는 문자열의 개수 (0) | 2024.06.18 |
원형테이블에 앉은 n명의 사람 중 서로 인접하지 않은 k명의 사람을 뽑는 방법 (0) | 2024.06.07 |
n명 중 k명을 중복해서 선택하는 중복조합의 수 이해하기 (0) | 2024.06.07 |