자기 것을 다시 갖지 않고 나눠주는 경우의 수 교란순열(완전순열) 배우기
1. 문제
2. 풀이
PS를 위한 수학 - 교란 순열(완전순열) - 와 이게 에러가 뜨네 (mjstudio.net)
비가 오는 날에 n명의 사람이 자기의 우산을 쓰고 한 건물에 모여있다.
모두 동시에 집에 가려고 다시 우산을 쓰고 나가려는데, 자신의 우산을 사용하지 않는 경우의 수는?
n개의 물건을 n명의 사람에게 다시 분배하는데, 자기 물건을 다시 갖지 않는 경우의 수를 교란순열(완전순열, derangement)라고 부른다
점화식이 유명한데 (고등학교때부터..)
n = 0인 경우 생각할 필요도 없이 $a_{0} = 0$
n = 1인 경우 자기 자신 것만 가지게 되므로 $a_{1} = 0$
n = 2인 경우 서로 남의 것만 가지면 되므로 $a_{2} = 1$
$n \geq 3$인 경우, $i$번째 사람이 $j$번째 사람의 물건을 가져갔다고 가정하자.
$j$번째 사람이 $i$번째 사람의 물건을 가져갔다면,
$i,j$ 2명의 사람은 물건을 가져갔으므로 나머지 n-2명의 사람이 자기 것을 가져가지 않는 경우의 수는 $a_{n-2}$
이번엔 $j$번째 사람이 $i$번째 사람의 물건을 가져가지 않았다면, $i$번째 사람 1명만 결정되었고,
나머지 n-1명이 자기 것을 가져가지 않는 경우의 수는 $a_{n-1}$
즉, $i$번째 사람이 $j$번째 사람의 물건을 선택했을때 나타나는 경우의 수는 $a_{n-1}+a_{n-2}$
그런데 $j$로 가능한 경우는 $i$를 제외한 n-1가지이므로... 전체 경우의 수는 $(n-1)(a_{n-1} + a_{n-2})$
그래서 일반적으로..
$$a_{0} = a_{1} = 0, a_{2} = 1, a_{n} = (n-1)(a_{n-1} + a_{n-2}), n \geq 3$$
그러면 간단한 다이나믹 프로그래밍으로 문제를 해결할 수 있다
mod = 1000000000
n = int(input())
dp = [0]*(n+1)
if n >= 2:
dp[2] = 1
for i in range(3,n+1):
dp[i] = (i-1)*(dp[i-1]+dp[i-2])
dp[i] %= mod
print(dp[n] % mod)
'조합론' 카테고리의 다른 글
원형테이블에 앉은 n명의 사람 중 서로 인접하지 않은 k명의 사람을 뽑는 방법 (0) | 2024.06.07 |
---|---|
n명 중 k명을 중복해서 선택하는 중복조합의 수 이해하기 (0) | 2024.06.07 |
적어도 1명 이상이 자기 자신 것을 그대로 가져갈 확률은?(교란순열의 수렴) (0) | 2024.05.08 |
DP가 불가능할 때 특정 위치 (x,y)로 이동하는 경우의 수를 구하는 다른 방법 (0) | 2024.04.05 |
주어진 순열의 다음 순열을 효과적으로 찾는 방법(next permutation, prev_permutation) (0) | 2024.03.12 |