递归(DFS)与回溯的编程

今天看了吴永辉老师讲的递归与回溯的编程课,记录一下。(本来想把课件发出来的,不知道怎么发)
递归的回溯定义就不再多说了,直接看题吧。

1、计算递归函数的实验范例

计算递归函数的实验范例的大致解题思路。
在这里插入图片描述
放苹果 POJ 1664 http://poj.org/problem?id=1664
递归式
老师的思路写的非常棒,如图。
在这里插入图片描述
下面是我个人整理后用自己的语言叙述的:

  • 设f(m,n)是m个苹果放在n个盘子李的总共放法数量。 首先很容易分成两种情况,n>m,n<m;

  • n>m 盘子数大于苹果数,故肯定有n-m个盘子空着也就是对放法无影响,根据题意 1 5 1 与5 1 1是同一种方法可知,与放得顺序无关,故f(m,n)=f(m,m);

  • n<=m时,可以分为有空盘子,和没有空盘子两种情况。

  • 有空盘子即f(m,n-1),我开始并没理解为啥n-1,感觉它可以空好多盘子,后来才逐渐意识到它是递归,所以一直递归下去,就将空1个盘子,空2个盘子…空n个盘子的情况都枚举出来了。

  • 无空盘子,即f(m-n,n),即每个盘子至少放一个,还剩下m-n个苹果没放,故f(m,n)的放法数,取决于剩下m-n个苹果放在n个盘子里的放法数。

递归边界
在这里插入图片描述
有了这些我们就可以愉快的敲代码了。
AC代码

#include<iostream>
using namespace std;
int dfs(int m,int n)
{
    
    
	if(n==1||m==0)
		return 1;
	if(n>m)
		return dfs(m,m);
	else{
    
    
		return dfs(m,n-1) + dfs(m-n,n);
	}
}
int main()
{
    
    
	int n,m,t;
	cin>>t;
	while(t--){
    
    
		cin>>m>>n;
		cout<<dfs(m,n)<<endl;
	}
	return 0;
 } 

2、求解递归数据的实验范例

Symmetric Order POJ 2013 http://poj.org/problem?id=2013

题目大意在这里插入图片描述在这里插入图片描述
试题解析
在这里插入图片描述
非递归方法

老师的描述
在这里插入图片描述
个人的描述
在这里插入图片描述
如图竖线代表在上方,横线代表在下方,上方均为从第1行开始隔行输出下方很容易发现,偶数行时下方是从第n行开始隔行输出的,奇数行时是从n-1行开始输出的。
所以很容易的出代码
非递归AC代码

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
    
    
	int n,cnt=0;
	string str[1000];
	while(~scanf("%d",&n) && n != 0)
	{
    
    
		cnt++;
		for(int i = 1 ; i <= n ; i++ )
		{
    
    
			cin>>str[i];
		}
		cout<<"SET "<<cnt<<endl;
		for(int i = 1 ; i <= n ; i+=2 )
		{
    
    
			cout<<str[i]<<endl;
		}
		if(n%2==0){
    
    
			for(int i = n ; i>=2 ; i-=2 ){
    
    
				cout<<str[i]<<endl;
			}
		}else{
    
    
			for(int i = n-1; i>=2 ; i-=2){
    
    
				cout<<str[i]<<endl;
			}
		}
	}
	return 0;
}

递归方法

老师的描述
在这里插入图片描述
个人的描述
将n个字符串分为 s[1]s[2] 、s[3]s[4]…s[n-1]s[n] n/2组,将s[1]、s[3]…s[n-1]直接输出,剩下的进行递归,递归类似与压栈,故输出为s[n] … s[4] s[2];递归边界易知当n为0时;

递归AC代码

#include<iostream>
using namespace std;
void dfs(int n)
{
    
    
	string s;
	cin>>s;		//每组的第一个直接输出
	cout<<s<<endl;
	if(--n){
    
    	//判断这一组是否成对,即每组的第二个元素是否存在
		cin>>s;
		if(--n)	dfs(n);		//若后面还有其它组着压栈,没有直接输出,开始出栈。
		cout<<s<<endl;		
	}
}
int main()
{
    
    
	int n,cnt=0;
	while(cin>>n){
    
    
		if(n==0)	break;
		cnt++;
		cout<<"SET "<<cnt<<endl;
		dfs(n);
	}
}

3、用递归算法求解问题的实验范例

Fractal POJ 2083 http://poj.org/problem?id=2083
题目大意:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目解析
在这里插入图片描述
个人描述:
根据题目的样例,很容易知道n度的盒分形图的规模为3^(n-1)的正方形,n-1度的盒分形分别位于左上,左下,右上,右下,中间。x,y为左上角坐标,然后进行对应坐标运算递归即可。
AC代码

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
char mp[735][735];
void dfs(int n , int x,int y)
{
    
    
	if(n==1){
    
    
		mp[x][y]='X';
		return ;
	}
	int m = pow(3,n-2);		//注意3^(n-2)
	dfs(n-1,x,y);///左上角 
	dfs(n-1,x,y+2*m);//右上角 
	dfs(n-1,x+m,y+m);//中间 
	dfs(n-1,x+2*m,y);//左下角 
	dfs(n-1,x+2*m,y+2*m);///右下角 
}
int main()
{
    
    
	int n;
	while(cin>>n){
    
    
		if(n==-1)		break;
		memset(mp,' ',sizeof(mp));	///注意初始化,否则会wa
		dfs(n,1,1); 
		int m=pow(3,n-1);
		for(int i = 1 ; i<=m;i++)
		{
    
    
			for(int j = 1 ; j<=m ;j++)
				cout<<mp[i][j];
			cout<<endl;
		}
		cout<<"-"<<endl;
	}
	return 0;
}

没写全,想要全部课件的可以私信我。

猜你喜欢

转载自blog.csdn.net/weixin_45822897/article/details/107405576