递推
基本概念
直接或者间接调用自身的算法称为递归算法
一般数据 n<=30
用递归
步骤
优缺点
优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性。因此它为设计算法、调试程序带来很大方便。
缺点:运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。
典型例题
- 求 n 的阶乘
- 求 斐波那契数列
- 求 二叉树相关内容 ⭐
- 汉诺塔问题
- 排列 问题
ACWing 练习题
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
int n;
int a,b=1,c;
int main()
{
scanf("%d",&n);
while(n--){
printf("%d ",a);
c=a+b;
a=b,b=c;
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 16;
int n;
int status[N];//0 表示未使用 1表示选中 2表示未选中
void dfs(int u)
{
if(u > n)//判断边界
{
for (int i = 1; i <= n; i ++ )
{
if(status[i]==1) cout<<i<<" ";
}
puts("");
return ;//一定要结束
}
status[u]=1;
dfs(u+1);
status[u]=0;
status[u]=2;
dfs(u+1);
status[u]=0;
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10;
int n;
int sta[N];//表示位置 0 未使用 1 ~ n 放了数
bool used[N];//默认是0 0 是未使用 1 是已使用
void dfs(int u)
{
if (u > n)
{
for(int i = 1; i <= n;i++) printf("%d ",sta[i]);
puts("");
return;
}
for (int i = 1; i <= n; i ++ )//遍历枚举分支 因为有多个分支
{
if(!used[i])
{
used[i]=true;
sta[u]=i;//把该数放入
dfs(u+1);
used[i]=false;//恢复现场
sta[u]=0;
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 30;
int n,m;
int sta[N];
void dfs(int u,int start)
{
if(u+n-start <m) return;//剪枝
if(u==m+1) //u 从1开始 到 m+1 刚好是 m 个数
{
for (int i = 1; i <= m; i ++ ) printf("%d ",sta[i]);
puts("");
return;
}
for (int i = start; i <= n; i ++ )
{
sta[u]=i;
dfs(u+1,i+1);
sta[u]=0;//恢复现场
}
}
int main()
{
cin>>n>>m;
dfs(1,1);
return 0 ;
}
1209. 带分数(难)⭐⭐⭐
暴力可以做
优化一下 dfs嵌到也可以做 但是费时
- 思路
看成三个数,根据公式能推出 cn=ca+b,因此只需求出c和a就能得出b 缩小了复杂度
因此先 枚举a,然后枚举c,最后判断b是否成立
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int n, ans;
bool st[N]; //记录是否使用
bool backup[N]; //备份数组
bool check(int a, int c) //求 b 的值,并且判断没有重复 而且和符合要求
{
long long b = n * (long long)c - a * c;
if (!a || !b || !c) //都不为0
return false;
memcpy(backup, st, sizeof st); //复制数组
while (b)
{
int x = b % 10; //取个位数
b /= 10; //缩小
if (!x || backup[x]) //判断 x 是否为0 或是 x 是否被用过
return false;
backup[x] = true;
}
for (int i = 1; i <= 9; i++) //看b 有没有重复的
if (!backup[i])
return false;
return true;
}
void dfs_c(int u, int a, int c)
{
if (u > 9) //如果十个数都用了
return;
if (check(a, c)) //看是否符合要求
ans++;
for (int i = 1; i <= 9; i++)
{
if (!st[i])
{
st[i] = true;
dfs_c(u + 1, a, c * 10 + i);
st[i] = false; //恢复现场
}
}
}
void dfs_a(int u, int a)
{
if (a >= n) //这不是边界
return;
if (a)
dfs_c(u, a, 0);
for (int i = 1; i <= 9; i++)
{
if (!st[i])
{
st[i] = true;
dfs_a(u + 1, a * 10 + i);
st[i] = false;
}
}
}
int main()
{
cin >> n;
dfs_a(0, 0); //第一个表示当前位置 第二个是a的值
cout << ans << endl;
return 0;
}