算法学习第九篇
谈到递归,就要谈谈分治,分治也叫分而治之,意为将一个大问题分解为若干个小问题然后逐个击破,最后合并所以子问题的解得到原问题的解,总体概括出来就是三步:分解、解决、合并,但需要注意的就是我们面对的子问题应该是相互独立的。
递归
递归思想是很适合用于实现分治算法的,子问题的求解过程相同,则我们可以通过重复调用自身的函数,从而得到我们想要的答案,虽然使用递归算法在实际编程中不太推崇主要是因为时间复杂度太高,对于实际的项目编写效率低,,但这种解题思想是非常值得推崇的,包括后面的动态规划问题也是有所体现的。在实现递归时候必须注意两个必要点①边界设置②递归式(也就是分解为若干子问题的手段)
比较经典的例子就是斐波那契数列问题,斐波那契数列是满足f(0)=1,f(1)=1,f(n)=f(n-1)+f(n-2)的数列,显然如果我们求解f(n)就可以分解为求解f(n-1)和f(n-2),以此类推继续求解下去,遵从f(n)=f(n-1)+f(n-2)即可。代码如下
#include <cstdio>
int f(int n)
{
if(n==0||n==1)
return 1;
else
return f(n-1)+f(n-2);
}
int main()
{
int n;
scanf("%d", &n);
printf("%d", f(n));
return 0;
}
全排列问题
全排列:把1~n的n个整数进行不同顺序排列,所有的排列组合成为全排列,例如(1,2,3,4)全排列为(1234)(1243)(1324)(1342)(1423)(1432)(2134)(2143)(2413)(2431)(2314)(2341)(3124)(3142)(3412)(3421)(3214)(3241)(4123)(4132)(4213)(4231)(4312)(4321)
分析:首先思考边界,定义数组a[n]当做我们的存储数组用来存储得到的排列,定义j为数组下标,也是我们要处理的下标位置,依次递增,增大到n+1是其实已经完成所有的处理,所以边界就是j==n+1,当j==n+1时候输出当前序列,第一步已经解决。第二就是思考递归式,从数组第一位开始着手,从1~n里面选择一个作为首位,但进行到第二位时候怎么排除已经使用过的第一位的数字呢,答案很简单——散列,先定义一个散列hashtable[n],里面都置为false,当使用一个数字后就在该数字位置置为true,分析完了之后,递归继续进行下一位的分析,代码如下:
#include <cstdio>
const int max=20;
int n, a[max], hashtable[max]={false};
void quanpai(int j)
{
if(j==n+1) //j相当于a数组指针
{
for(int i=1;i<=n;i++) //边界
{
printf("%d", a[i]);
}
printf(" ");
return;
}
for(int x=1;x<=n;x++)
{
if(hashtable[x]==false)
{
a[j]=x;
hashtable[x]=true;
quanpai(j+1);
hashtable[x]=false;
}
}
}
int main()
{
scanf("%d", &n);
quanpai(1);
return 0;
}
皇后问题
待更..