TSOJ 花心的小虎——欧拉错信问题

原题信息

题目描述:

小虎在网上结交一批女网友,在今年情人节那天,小虎想玩浪漫,同时给n个女网友每人写了一封各有特色的情书,然而由于过分激动,他竟然把所有的信都装错了信封!计算将所有的信都装错信封,共有多少种不同情况?例如,3封信全装错信封的种数为2,即231和312

输入描述:

输入包含若干组数据。每组数据是一个整数N(1<=N <=30),表示小虎写信的封数

输出描述:

对于每组数据,在单独的一行输出一个整数,标识所有的信都装错信封的种数

样例输入:

3
5

样例输出:

2
44

初次AC思路——暴力搜索

本题长得很像一个全排列问题,但是有一点与全排列不同:
全排列要求输出一棵树的所有分支结果,而本题的条件层数不等于编号大大减少了搜索的次数。
以3为例,搜索路径如下:

在这里插入图片描述
在这里插入图片描述
依据这棵树,得出如下AC代码:

#include<stdio.h>
int flag[31],N;
long long count;
void DFS(int i)
{
	int j;
	if(i==N)
	{
		count++;
		return;
	}
	else
	{
		for(j=1;j<=N;j++)
		if(flag[j]==0&&j!=i+1)
		{
			flag[j]=1;
			DFS(i+1);
			flag[j]=0;
		}
	}
	return;
}
int main()
{
	int i;
	while(scanf("%d",&N)!=EOF)
	{
		for(i=1;i<=N;i++)
			flag[i]=0;
		count=0;
		DFS(0);
		printf("%d\n",count);
	}
	return 0;
} 

高效思路——错位重排

一看提交状态,同样是AC,我是184MS,大犇0MS,这里面一定有猫腻。
于是,经过请教大犇,我得到了一种新思路:欧拉错信原理——错位重排。


错位重排:
引用百科里的话:

错位重排是指一种比较难理解的复杂数学模型,是伯努利和欧拉在错装信封时发现的,因此又称伯努利-欧拉装错信封问题。

对于第n封信,我们可以把它放在第k的位置上,对于k,我们有两种放法:
(1)放在n的位置上,如此其余n-2封信又是一个新的子问题,而这样选定k的方法有n-1种;
(2)不放在n的位置上,而是像放第n封信是一样,放在k’的位置上,这样就变成了n-1问题,而这样选定k的方法有n-1种。

综上,设数列F(n)满足以上规律,F(n)的递推式为:
在这里插入图片描述
(形似斐波那契数列)


根据该递推式,我写出了代码:

#include<stdio.h>
int main()
{
	long long Ou_La_Niu_Bi[31],n,i;
	while(scanf("%lld",&n)!=EOF)
	{
		Ou_La_Niu_Bi[1]=0;
		Ou_La_Niu_Bi[2]=1;
		for(i=3;i<=n;i++)
			Ou_La_Niu_Bi[i]=(i-1)*(Ou_La_Niu_Bi[i-1]+Ou_La_Niu_Bi[i-2]);
		printf("%lld\n",Ou_La_Niu_Bi[n]);
	}
	return 0;
}

不仅代码变短了,连耗时也变成了0ms。
欧拉老人家没事装错个信都能想到数学问题,还能优化代码,牛啤!

F(n)的通项公式

这道编程题算是告一段落了,但是我们对错排问题的探索还没结束,F(n)的递推式是什么?
由递推式
F(n)=(n-1)[F(n-1)+F(n-2)],记为式(1);
由式(1)得到
F(n)-nF(n-1)=-[F(n-1)+(n-1)F(n-2)],记为式(2);
设G(n)=F(n)-nF(n-1),记为式(3);
由上方式(2)式(3)得出
G(n)=-G(n-1),
由于G(2)=1,
所以G(n)=(-1)n
也即F(n)=(-1)n+nF(n-1),记为式(4);
也即:
在这里插入图片描述
设:
在这里插入图片描述
那么
H(n)=1-nH(n-1)
对等式两边同时除以n!,可得
在这里插入图片描述
从n倒推到1,分别记为式(1),(2)…(n),奇数式总和减偶数式总和,得
在这里插入图片描述

通过这一系列推导,得出通项公式
在这里插入图片描述


推导出通项公式后,我的内心只剩下:
在这里插入图片描述
以及:
在这里插入图片描述
2018/12/03

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值