算法很美——深入递归(深搜,回溯,减枝等)
逐步生成结果之数值型问题
双管齐下解递归——自上而下,自下而上
通常,我们写递归采用的是自上而下(分治法)
自上而下步骤:分解为子问题,递归求解子问题,合并
自下而上(递归,数学归纳法,动态规划):
- 解决简单情况下的问题
- 推广到复杂情况下的问题
- ···
- 如果递归次数很明确,可迭代代替(循环)
- 如果有封闭形式,可以直接求解
自下而上找出递推公式,从而用自上而下的方法求解或用迭代
例题 - 上楼梯
#include <iostream>
#include <bits/stdc++.h>
long long fun(int n)
{
if(n==0)return 1;
return (fun(n-1)+fun(n-2)+fun(n-3))%1000000007;
}
int main()
{
int n;
while(scanf("%d",&n)!=-1)
printf("%lld\n",fun(n));
return 0;
}
//也可用迭代,三个一更新
可用三个变量保存后三个数,并不断更新
- 机器人走方格
#include <iostream>
#include <bits/stdc++.h>
int fun(int m,int n)
{
if(m==1||n==1)return 1;
if(m==0||n==0)return 0;
return fun(m-1,n)+fun(m,n-1);
}
int main()
{
int m,n;
while(scanf("%d %d",&m,&n)!=-1)
printf("%d\n",fun(m,n));
return 0;
}
为提高时间效率,可采用迭代
两个变量,所以用二维数组记录
#include <iostream>
#include <bits/stdc++.h>
int fun(int m,int n)
{
int a[m+1][n+1];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(i==1||j==1)a[i][j]=1;
else a[i][j]=a[i-1][j]+a[i][j-1];
}
}
return a[m][n];
}
int main()
{
int m,n;
while(scanf("%d %d",&m,&n)!=-1)
printf("%d\n",fun(m,n));
return 0;
}
- 硬币表示
递归思路:分步,每种面值各要几张
#include <iostream>
#include <bits/stdc++.h>
//1,2,5,10,25
//递归
int arr[]={1,5,10,25};
int fun(int n,int cur)
{
if(cur==0)return 1;
int res=0;
for(int i=0;i*arr[cur]<=n;i++)
res+=fun(n-i*arr[cur],cur-1);
return res;
}
int main()
{
int i=1;
while(i<=100){
int res=fun(i,3);
printf("%d__%d\n",i,res);
i++;
}
return 0;
}
迭代思路:要素:n,max
所以采用二维数组:f(n)=f(n-max)+f(n-2*max)+…
#include <iostream>
#include <bits/stdc++.h>
//1,2,5,10,25
//递归
int arr[]={1,5,10,25};
void fun(int n)
{
int a[4][101];
for(int i=0;i<=3;i++)
{
for(int j=0;j<101;j++){
a[i][j]=0;
if(i!=0&&j!=0)
for(int k=0;k*arr[i]<=j;k++)
a[i][j]+=a[i-1][j-k*arr[i]];
else a[i][j]=1;
}
}
for(int i=1;i<101;i++)
printf("%d__%d\n",i,a[3][i]);
}
int main()
{
fun(100);
return 0;
}