训练/递推/递归
训练/递推/递归
递归前先了解一个全排列问题。
就是生成一个全排列
#include<iostream>
using namespace std;
const int maxn=11;
int n,p[maxn],h[maxn];
void generateP(int index) //index表示已经添加了多少位数
{
if(index==n+1)
{
for(int i=1;i<=n;i++)
cout<<p[i]<<" ";
cout<<endl;
return ;
}
for(int x=1;x<=n;x++)
{
if(h[x]==0)
{
p[index]=x; //给每个全排列添加,x
h[x]=1; //表示x已经添加过
generateP(index+1); //递归
h[x]=0; //递归完毕后无其它结果,回溯
}
}
}
int main()
{
cin>>n;
generateP(1);
return 0;
}
然后其实用algorithm头文件下的东西也可以很简单生成全排列,就是一个比较简单的递归思维
#include<iostream>
#include<algorithm>
using namespace std;
int a[20];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
a[i]=i;
do{
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
cout<<endl;
}while(next_permutation(a+1,a+n+1));
return 0;
}
一道DFS深度优先搜索题
题目链接
洛谷P1135
题意:有n层楼,现在在a楼目标去b楼需要计算a楼去b楼的最短操作次数。每次操作可操作在a楼的一个数k[a],上升k[a]或下降k[a]
BFS其实也能过,
题解:
BFS广度搜索
队列存有当前位置,还有走到当前位置的步数
将第一个位置进队列,将此处标记上走过,然后从这个位置有向下或者向下,向上走k[a]层后,在当前走过的步数前提下+1,并且将次层标记为1,防止死循环
另一种情况,在当前位置向下走k[a]个阶梯,当前走过的步数+1,并将此层标记为1,防止死循环。当队首元素为目标层后退出循环,求得。
代码:
#include<iostream>
#include<queue>
using namespace std;
struct node{
int floor;
int step;
};
int n,a,b;
int k[207];
int vis[207];
queue<node> q;
int main()
{
cin>>n>>a>>b;
int i;
for(i=1;i<=n;i++)
cin>>k[i];
node e1,e2;
e1.floor = a;
vis[a] = 1;
e1.step = 0;
q.push(e1);
while(!q.empty())
{
e2 = q.front();
q.pop();
if(e2.floor==b) break;
i=e2.floor+k[e2.floor];
if(i<=n && !vis[i])
{
e1.floor = i;
e1.step = e2.step+1;
q.push(e1);
vis[i]=1;
}
i=e2.floor-k[e2.floor];
if(i>=1 && !vis[i])
{
e1.floor = i;
e1.step = e2.step+1;
q.push(e1);
vis[i]=1;
}
if(e2.floor==b) cout<<e2.step<<endl;
else cout<<-1<<endl;
return 0;
}
DFS题当然是用来训练深搜的
题解:
深搜一个now表示当前到达楼层,一个sum表示总次数,然后vis数组表示走未走过,无出路是记得回溯,回归为0状态即可
代码:
#include<iostream>
#include<cmath>
int n,a,b,sum;
int k[207],vis[207];
int ans=100000;
void dfs(int now,int sum)
{
int dx;
vis[now]=1;
if(now==b) ans=min(ans,sum);
dx = now+k[now];
if(dx<=n && !vis[dx])
dfs(dx,sum+1);
dx = now-k[now];
if(dx>=1 && !vis[dx])
dfs(dx,sum+1);
vis[now]=0;
}
int main()
{
cin>>n>>a>>b;
dfs(a,0);
if(ans==100000) cout<<-1<<endl;
else cout<<ans<<endl;
}
朴素的DFS注意变换起始位置即可
题目链接
洛谷P1036
题目思路,每次改变位置计算到的位置dfs吧
代码:
#include<iostream>
using namespace std;
bool isprime(int n)
{
int(i=2;i*i<=n;i++)
if(n%i==0) return false;
return true;
}
int n,k,ans;
void dfs(int num,int sum,int start)
{
if(num==k)
{
if(isprime(sum) ans++;
return ;
}
for(int i=start;i<=n;i++)
dfs(num+1,sum+a[i],i+1);
return;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dfs(0,0,1);
cout<<ans<<endl;
return 0;
}
洛谷P1057
题目链接
洛谷P1057
解法记忆化搜索
//不太会。。。
#include<iostream>
#include<cstring>
using namespace std;
int f[31][31],n,m;
void dfs(int s,int c)
{
f[s][c]=0;
if(c==m && s==1)
f[s][c]=1;
if(c!=m){
if(f[s%n+1][c+1]==-1) dfs(s%n+1,c+1);
if(f[s!=1?s-1:n][c+1]==-1) dfs(s!=1?s-1:n,c+1);
f[s][c]=f[s%n+1][c+1]+f[s!=1?s-1:n][c+1];
}
}
int main()
{
cin>>n>>m;
memset(f,-1,sizeof(f));
dfs(1,0);
cout<<f[1][0];
return 0;
}
洛谷P2513
思路:
//dp不太会
以下仅是70分的暴力dp
#include<iostream>
using namespace std;
int n,k;
const int mod=10000;
int f[1005][10005];
int main()
{
cin>>n>>k;
f[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int p=0;p<=k;p++)
{
for(int j=0;j<=i-1;j++)
{
f[i][p+j] += f[i-1][p];
f[i][p+j] %= mod;
}
}
}
cout<<f[n][k];
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)