大家好,这两天时间比较充裕,我可以有很多的时间来写代码,真是一件幸福的事,时间比较多,可浪费的时间也比较多,等这个星期忙完了,我也要开始我的coursea之旅了,废话不多说了,直接进入主题——递归算法的总结。
先从两道题目说起:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5660 Accepted Submission(s): 1755
There are many students in PHT School. One day, the headmaster whose name is PigHeader wanted all students stand in a line. He prescribed that girl can not be in single. In other words, either no girl in the queue or more than one girl stands side by side. The case n=4 (n is the number of children) is like
FFFF, FFFM, MFFF, FFMM, MFFM, MMFF, MMMM
Here F stands for a girl and M stands for a boy. The total number of queue satisfied the headmaster’s needs is 7. Can you make a program to find the total number of queue with n children?
There are multiple cases in this problem and ended by the EOF. In each case, there is only one integer n means the number of children (1<=n<=1000)
For each test case, there is only one integer means the number of queue satisfied the headmaster’s needs.
这道题目一入手,我就开始比划了,我还没有想到为什么要用到递归,就顺着题目的思路,希望可以直接求解,就这样一股脑的写出了下面的代码,猛然发现写不下去了。
#include
//还是有问题啊,出不来
//没看到递归的运用
using namespace std;
int a[1000];
int n =0;
int calculateFactorial(int p)
{
int sum = 1;
for(int i =0;i<=p;++i)
{
sum = sum * i;
}
return sum;
}
int calculateCombination(int m1,int m2)
{
int a1 = calculateFactorial(m1);
int a2 = calculateFactorial(m2;
int a3 = calculateFactorial(m1-m2);
return a1 / (a2 * a3);
}
int getCount(int p)
{
int time = 0;
int sum = 0;
if(p%2 == 0)
{
time = p / 2;
}
else{
int a1 = p - 3;
int temp = a1;
if(a1 == 0)
time = 1;
else{
time = 1;
sum += n - p + 1;
for(int i =0;i<(a1/2);++i)
{
time += temp / 2;
for(int j = 0;j> n;
for(int i =0;i
递归算法的思想是:把规模大的较难解决的问题转化成规模较小的,以解决的同一问题,规模较小的问题又可以转化成规模更小的问题,直到可以直接得出他们的解,从而得到原问题的解。
一个问题要采用递归方法来解决时,必须符合以下三个条件:
1.解决问题时,可以把一个问题转化为一个新的问题,而这个新的问题的解决方法仍与原问题的解法相同,只是所处理的对象有所不同,这些被处理的对象之间是有规律的递增或递减;
2.可以通过转化过程是问题得到解决;
3.必定要有一个明确的结束递归的条件,否则递归将会无止境地进行下去,直到耗尽系统资源。也就是说必须要某个终止递归的条件。如求阶乘问题,我们要求n的阶乘(n!),可以把这个问题转化为n*(n-1)!,而要求(n-1)!又可转化为(n-1)*(n-2)!,……,这里面都有一个一个数乘以另一个数阶乘的问题,被处理的对象分别是n,n-1,……,是有规律的递减。但是我们不能让程序无休止的乘下去,必须要给他一个结束条件,该问题恰好有一个结束条件,那就是当n=0时,0!=1。
我之所以上面的代码求不出来,就是因为原问题的过程复杂,不能直接求解,上面给出的采用递归解题的条件在我看来略显复杂,其实如果可以一句话总结的话,那就是:能很方便地写出递归表达式的题目采用递归算法都会异常简便。
上面那道题目的递归表达式很不好理解,也应该是那道题的难点,我写一下我的理解:
F(n)表示n个人的合法队列,在具体分析之前,我们应该知道,合法队列+合法队列还应该是合法队列,但是不合法队列加上合法队列也可以是合法队列
按照最后一个人的性别分析,他要么是男,要么是女,所以可以分两大类讨论:
1、如果n个人的合法队列的最后一个人是男,则对前面n-1个人的队列没有任何限制,他只要站在最后即可,所以,这种情况一共有F(n-1);
2、如果n个人的合法队列的最后一个人是女,则要求队列的第n-1个人务必也是女生,这就是说,限定了最后两个人必须都是女生,这又可以分两种情况;
2.1、如果队列的前n-2个人是合法的队列,则显然后面再加两个女生,也一定是合法的,这种情况有F(n-2);
2.2、但是,难点在于,即使前面n-2个人不是合法的队列,加上两个女生也有可能是合法的,当然,这种长度为n-2的不合法队列,不合法的地方必须是尾巴,就是说,这里说的长度是n-2的不合法串的形式必须是“F(n-4)+男+女”,这是难点,我再解释一下,为什么这个不合法串的形式必须是这种形式,其实我上面提到了,这个不合法队列必须是能够加上一个合法队列变成合法队列的。
这种情况一共有F(n-4).
所以,通过以上的分析,可以得到递推的通项公式: F(n)=F(n-1)+F(n-2)+F(n-4) (n>3)然后就是对n<=3 的一些特殊情况的处理了,显然:F(0)=1 (没有人也是合法的,这个可以特殊处理,就像0的阶乘定义为1一样) F(1)=1 F(2)=2 F(3)=4
最后附上代码:
#include
using namespace std;
int n = 0;
int recursion(int p)
{
if(p == 1)
return 1;
else if(p == 2)
return 2;
else if(p == 3)
return 4;
else if(p == 4)
return 7;
else{
return recursion(p-1)+recursion(p-2)+recursion(p-4);
}
}
int main()
{
cin >> n;
cout << recursion(n);
return 0;
}
#include
using namespace std;
int sum = 0;
int realRecursion(int n)
{
if(n == 3)
{
return 6;
}
else if(n == 2)
{
return 6;
}
else if(n == 1)
{
return 3;
}
else{
return realRecursion(n-1) + 2*realRecursion(n-2);
}
}
int main()
{
int n;
cin >> n;
sum = realRecursion(n);
cout << sum;
return 0;
}
通过二叉树来体会,我觉得是最好的理解方法了,不足之处,希望大家多多指正,多多留言!