机试算法讲解: 第48题 递推之写信发错啦

/*
问题:给N个网友写信,所有信全部装错信封有多少种可能的错误方式
输入:n(1<n<=20)
输出:错误的方式
输入:
2
3
输出:
1
2
递推求解:n=1,0种,n=2,1种,n=3,2种,n=4,8种。设F[n]为n个信封的装错方式总数。
         假设n号信封装的是k号信封,而n号信封中的信装在m号信封里。将k==m分为两类
		 1)若k!=m,交换n号信封和m号信封,则n号信封对了,m号信封中是装的k号信,即除n号信封外,其余n-1个信封全部装错。装错方式为F[n-1]。又由于m的n-1个可能取值
		 这类装错方式总数为(n-1)*F[n-1]。在n-1个信封装错的F[n-1]基础上,将n号信封所装的信与n-1个信封中任意一个信封(n-1中选择)所装的新交换,所得信全部错误。
		 2)若k=m,交换n号信和m号信后,n号信封和m号中恰好对了,除它们之外剩余的n-2个信封全部装错,装错方式为F[n-2],又由于m的n-1个取值,装错方式总数为
		 (n-1)*F[n-2]。可理解为在n-2个信封全部装错基础上,交换n号信封和1到n-1号信封中任意1刚和,共有n-1种选择。
关键:
1 错排公式F[n]={0,n=1
               {1,n=2
			   {(n-1)*F[n-1] + (n-1)*F[n-2],n>=2
2 递推求解技巧:逆推,从倒数第二步或者倒数第一步如何到达最终状态,找到递推关系式
3 递推求解往往数值较大,用long long 或 _int64 ,打印用%ld
4 分析问题,将每一个问题分割成规模较小的几个问题,分割过程要不遗漏和不重复,要得到递推关系式
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 21

int main(int argc,char* argv[])
{
	_int64 F[N];
	F[1] = 0;
	F[2] = 1;
	for(int i = 3 ; i <= N ; i++)
	{
		F[i] = (i-1)*F[i-1] + (i-1)*F[i-2];
	}
	int n;
	while(EOF!=scanf("%d",&n))
	{
		printf("%ld\n",F[n]);
	}
	system("pause");
	getchar();
	return 0;
}

你可能感兴趣的:(递推,机试算法)