训练/递推/递归

训练/递推/递归

递归前先了解一个全排列问题。
就是生成一个全排列

#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;
}
posted @   爱xiaoyi  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示