题目描述
某人写了 n 封信和 n 个信封,如果所有的信都装错了信封。求所有信都装错信封共有多少种不同情况。
输入格式
一个信封数 n,保证 n≤20。
输出格式
一个整数,代表有多少种情况。
输入输出样例
输入 #1
2
输出 #1
1
输入 #2
3
输出 #2
2
说明/提示
对于 100% 的数据,1≤n≤20。
思路:
我们假设一个数组dp[27],我们需要推出有n个信封的时候排错的可能,举例,首先第i个信封放在了k位置上,分为两种情况。
- 情况一 :原本应该放在位置
k
上的信封也恰好被放置在了位置i
上。因此,这种情况下剩下的n-2
个信封需要全部错排,即dp[i-2]
种方式。 - 情况二 :原本应该放在位置
k
上的信封不在位置i
上。所以剩下的i-1
个信封的错排数实际上是dp[i-1]
。 - 由于这两种情况是互斥的(即它们不能同时发生),所以我们将它们的结果相加,并乘以
(i-1)
(因为我们有i-1
种方式将第i
个信封放置到其他位置上),从而得到递推关系:dp[i] = (i-1) * (dp[i-1] + dp[i-2])
。
代码如下:
#include<iostream>
using namespace std;
typedef long long ll;
ll dp[27];
int main()
{
ll n;
cin >> n;
dp[0] = 1;
dp[1] = 0;
for(ll i = 2 ; i <= n ; i++)
{
dp[i] = (i-1)*(dp[i-1]+dp[i-2]);
}
cout << dp[n];
return 0;
}