递归练习:错排问题
/*====================================================================== 某人写了n封信和n个信封,如果所有的信都装错了信封。 求所有的信都装错信封共有多少种不同情况? 分析: 这个涉及到组合数学里面的错排问题。先看下面的例题。 组合学中有这样一个问题:某人给五个朋友写信,邀请他们来家中聚会。请柬和信封交由助手去处理。 粗心的助手却把请柬全装错了信封。请问:助手会有多少种装错的可能呢? 这个问题是是由当时有名的数学家约翰·伯努利(Johann Bernoulli,1667—1748)的儿子 丹尼尔·伯努利(Danid Bernoulli,17OO一1782)提出来的。 瑞士著名数学家欧拉按一般情况给出了一个递推公式: D(n) = (n-1) [D(n-2) + D(n-1)] 特殊地,D(1) = 0, D(2) = 1. 例题: 用A、B、C……表示写着n位友人名字的信封,a、b、c……表示n份相应的写好的信纸。把错装的总数为记作D(n)。假设把a错装进B里了,包含着这个错误的一切错装法分两类: (1)b装入A里,这时每种错装的其余部分都与A、B、a、b无关,应有D(n-2)种错装法。 (2)b装入A、B之外的一个信封,这时的装信工作实际是把(除a之外的)n-1份信纸b、c……装入(除B以外的)n-1个信封A、C……,显然这时装错的方法有D(n-1)种。 总之在a装入B的错误之下,共有错装法D(n-2)+D(n-1)种。 a装入C,装入D……的n-2种错误之下,同样都有D(n-1)+D(n-2)种错装法,因此D(n)=(n-1)[D(n-1)+D(n-2)] 这是递推公式,令n=1、2、3、4、5逐个推算就能解答蒙摩的问题。 D(1)=0,D(2)=1,D(3)=2,D(4)=9,D(5)=44 答案是44种。 参见:http://www.cnblogs.com/huashanqingzhu/p/3524551.html ========================================================================*/

1 #include<stdio.h> 2 int D(int n); 3 int main() 4 { 5 int n; 6 scanf("%d",&n); 7 printf("%d",D(n)); 8 return 0; 9 } 10 int D(int n) 11 { 12 if(n==1) 13 { 14 return 0; 15 } 16 else if(n==2) 17 { 18 return 1; 19 } 20 else 21 { 22 return (n-1)*(D(n-2) + D(n-1)); 23 } 24 }
其实,像类似菲波纳吉数列这种双线递归(可以画出类似二叉树这样的递归树),会有许多重复计算的地方。
比如,计算D(i)=D(i-1)+D(i-2),其实可能D(i-1)和D(i-2)在前面或者后面都还有要用到的地方。
所以,为了避免出现重复计算,可以考虑把每一个D(i)的值保存到数组当中,要计算时直接先查表,查不到再考虑递归计算。(这个就是所谓的记忆搜索了吧)
当然,能不用递归的最好不用递归来做这种事情。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App