作业介绍

递归函数

什么是递归?

玄而由玄!

递归函数是一个可以自己调用自己的函数!

f(f(x))=x+5,f(x)=?f(f(x))=x+5,f(x)=?

斐波那契数列:f(n)=f(n1)+f(n2)\tt f(n)=f(n-1)+f(n-2)

递归是一门甩锅的艺术:

何老师有一天问了某位同学x斐波那契数列第五项是多少? 这位x同学非常善于巧妙的甩锅(超级懒),于是找来y和z问他们f(4)和f(3).y和z也不笨继续问别人,直到问到f(1)和f(2).

int f(int n) 
{
     if (n==1||n==2) return 1;
     return f(n-1)+f(n-2);
}

递归事实上是很慢!问题在于同一个问题重复问。以斐波那契数列算f(5)\tt f(5),f(3)\tt f(3)被重复询问了两次。所以递归的问题在于重复计算!

解决重复计算方法就是记忆化!

什么是记忆化?就是用空间来换时间,记录所有中间解的答案,当重复问一个之前已经得到答案的问题,直接返回其答案,保证同一个问题只问一次。

int F[50];
int f(int n) {
     if (F[n]) return F[n];
     if (n==1||n==2) return 1;
     return F[n]=f(n-1)+f(n-2); 
}

求组合数

Cnm=Cn1m1+Cn1m\tt C_n^m=C_{n-1}^{m-1}+C_{n-1}^m
#include<bits/stdc++.h>
using namespace std;

 
int C(int n,int m) {
	if (m==0) return 1;
	if (n<m)  return 0;
	if (n==m) return 1;
	return C(n-1,m)+C(n-1,m-1);
} 

int main() {
	cout<<C(5,2)<<' '<<C(5,3)<<endl;
	return 0;
}

递归解决不会回到同一个点的路径问题

比如说:只能向右或者向下的问题。

过河卒:

#include<bits/stdc++.h>
#define int long long
using namespace std;
bool a[21][21];
int f[21][21];
int dx[]={-1,-2,-2,-1,1,2,2,1};
int dy[]={-2,-1,1,2,2,1,-1,-2};
int F(int n,int m) {
	if (~f[n][m]) return f[n][m];
	if (a[n][m]) return 0;
	if (n == 0&& m == 0) return 1;
	int res = 0;
	if (n>0) res=F(n-1,m);
	if (m>0) res+=F(n,m-1);
	return f[n][m]=res;
}
signed main() {
	memset(f,-1,sizeof(f));
	int n,m,x,y;
	cin>>n>>m>>x>>y;a[x][y]=true;//被占用
	for (int i = 0 ; i < 8 ; i ++ ) {//马一步可以走到的位置 
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (nx<0||nx>n||ny<0||ny>m) continue;
		a[nx][ny]=true;//地图内部点 
	} 
	cout<<F(n,m)<<endl; 
	return 0;
}

深度优先搜索是递归的两个套路!

路径问题

所有关于起点到终点的问题!

递归模板是:

void DFS(当前点坐标) {

     if (当前点==终点) {
           return ;
     }
     枚举当前能够一步到达所有点(nx,ny)
         if ((nx,ny)合法) {
              标记(nx,ny)
              DFS(nx,ny)
              撤销标记(nx,ny)
         }
}

应用:数字三角形

#include<bits/stdc++.h>
using namespace std;


bool vis[1001][1001];
int a[1001][1001];
int f[1001][1001];
int n,ans;
//(1,1)->(x,y)->(n,i)
void DFS(int x,int y,int sum) {
//	cout<<x<<' '<<y<<' '<<sum<<endl;
	if (f[x][y]>=sum) return ;
	f[x][y]=sum;
	if (x==n) {
		ans = max(ans,sum);
		return ;
	}
	//x,y->x+1,y,x+1,y+1
	for (int i = 0 ; i <= 1; i ++ ) {
		if (vis[x][y+i]) continue;
		vis[x][y+i]=true;
		DFS(x+1,y+i,sum+a[x+1][y+i]);//当前这个函数会等待 
		vis[x][y+i]=false; 
	}
} 
int main() {
	cin>>n;
	for (int i = 1; i <= n ; i ++ ) 
	    for (int j= 1; j <= i ; j ++ )  cin>>a[i][j];
	DFS(1,1,ans=a[1][1]);
	cout<<ans<<endl; 
	return 0;
}

填数问题

模板:

DFS(当前所填数的下标)
{
    if (如果填完所有的数) {
         return ;
    }
   for (枚举所有可能的填的数) {
        填上去;标记所填;
       DFS(下一个位置);
        撤销标记;
    }
}

题目

状态
已结束
题目
1
开始时间
2024-1-25 0:00
截止时间
2024-2-2 23:59
可延期
24 小时