发邮件(错排问题)
题目链接
题目描述
:
NowCoder每天要给很多人发邮件。有一天他发现发错了邮件,把发给A的邮件发给了B,把发给B的邮件发给了A。于是他就思考,要给n个人发邮件,在每个人仅收到1封邮件的情况下,有多少种情况是所有人都收到了错误的邮件?
即没有人收到属于自己的邮件
输入:
2
3
输出:
1
2
思路
:
- DFS方法超时
int N=0; void dfs(int,int); int book[100]={0}; int main() { int n; scanf("%d",&n); dfs(0,n); printf("%d",N); } void dfs(int num,int n) { if(num==n) N++; else { int i; for(i=0;i<n;i++) if(book[i]==0&&i!=num) { book[i]=1; dfs(step+1,n); book[i]=0; } } }
- 分为两种情况:
第一种
:前n-1种均是错位的,将第n个和前n-1个任意一个交换都可以 D(n-1)种放法,由于 D(n-1)的每种放法都可以衍生出和第n个邮件交换的n-1种放法
,所以一共是(n-1)*D(n-1)种放法
第二种
:前n-1种,有n-2种均是错位的,有1个正确的(这个正确的可以是在前n-1个中的任意位置
),将这个正确的和第n个交换 ,变成错位,而除开正确的和第n个外剩下的n-2个有D(n-2)种放法,所以一共是(n-1)*D(n-2)种放法
代码如下:
// write your code here cpp #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std; int main() { int n=0; vector<long long> dp(21,0); dp[2]=1; for(int i=3;i<=20;i++) { dp[i]=(i-1)*(dp[i-1]+dp[i-2]); } while(cin>>n) { cout<<dp[n]<<endl; } return 0; }
`