蓝桥杯专题之递归+dfs+bfs篇

题目列表:

2013年:第39级台阶

2014年:李白打酒,地宫取宝

2015年:牌型种数

2016年:方格填数,剪邮票

2018年:全球变暖

2019年:迷宫

2020年:走方格,七段码

2022年模拟赛:2021变1的最短操作数

2022年第一次模拟赛:15级台阶

2022年国赛:扩散

1.第39级台阶

小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!

站在台阶前,他突然又想着一个问题:

如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?

请你利用计算机的优势,帮助小明寻找答案。

答案:51167078

分析:

注意我们用的是dfs的思想,而非递归的思想(递归太容易绕进去了,博主也深受其害^^)

从地面开始向上走,有两种走法,上一层和上两层

只要我当前的台阶数不超过39,就可以继续深搜,否则的话,没必要继续下去

代码:

#include
using namespace std;
int ans;
void dfs(int step,int n){
	if(n > 39){
		return;
	}
	if(step%2==0 && n==39){
		ans++;
		return;
	}
	dfs(step+1,n+1);
	dfs(step+1,n+2);
}
int main(){
	dfs(0,0);
    cout << ans;
	return 0;
}

2.李白打酒

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

无事街上走,提壶去打酒。 逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

答案:14

分析:

从家门口开始走,有两种可能,遇到店和遇到花

只要李白遇到店不超过5次,遇到花不超过9次,最后一次已确定,就可以继续深搜

代码:

#include
using namespace std;
int ans;
void dfs(int dian,int hua,int jiu){
	if(dian > 5 || hua > 9){
		return;
	}
	if(dian == 5 && hua == 9 && jiu == 1){
		ans++;
		return;
	}
	dfs(dian+1,hua,jiu*2);
	dfs(dian,hua+1,jiu-1);
}
int main(){
	dfs(0,0,2);
	cout << ans;
	return 0;
}

3.地宫取宝

题目描述

X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。

地宫的入口在左上角,出口在右下角。

小明被带到地宫的入口,国王要求他只能向右或向下行走。

走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。

当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。

数据格式

  输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)

  接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值

  要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。

例如,输入
2 2 2
1 2
2 1
程序应该输出
2

再例如,输入
2 3 2
1 2 3
2 1 5
程序应该输出
14

分析:

1.有三个参数,一个是坐标,一个是目前收集的宝物数目,一个是目前手里宝物中的最大价值

2.当(x,y)处的宝物的价值比我手里的最大价值大时,且我要拿,这是一种情况;剩下的就是另一种情况,虽然它比我手中的大但我不拿或我不能拿

3.当我到了终点,这时终点还没判断,终点需要单独判断,如果我已经拿了k件或者我拿了k-1件但终点的宝物价值比我手中的宝物价值大,我可以拿,也是k件

4.利用记忆化搜索简化时间复杂度,这里要注意因为我MaxV的初值设的是-1,而数组的下标不能有负数,所以我要加个偏移量1

代码: 

#include
#include
using namespace std;
const int N = 60;
const long long MOD = 1e9+7;
int n,m,k;
int v[N][N];
long long mer[N][N][15][15];
long long dfs(int x,int y,int cnt,int MaxV){
	if(x > n-1 || y > m-1 || cnt > k){
		return 0;
	}
	if(x == n-1 && y == m-1){
		if(cnt == k || (cnt == k-1 && v[x][y] > MaxV)){
			return 1;
		}
	}
	if(mer[x][y][cnt][MaxV+1] != -1){
		return mer[x][y][cnt][MaxV+1];
	}
	long long ans = 0;
	if(v[x][y] > MaxV){
		ans += dfs(x + 1, y, cnt + 1, v[x][y]) + dfs(x, y + 1, cnt + 1, v[x][y]); 
	}
	
	ans += dfs(x + 1, y, cnt, MaxV) + dfs(x, y + 1,cnt, MaxV);
	return mer[x][y][cnt][MaxV+1] = ans%MOD;
}
int main(){
	cin >> n >> m >> k;
	for(int i = 0;i < n;i++){
		for(int j = 0;j < m;j++){
			cin >> v[i][j];
		}
	}
	memset(mer,-1,sizeof(mer));
	cout << dfs(0,0,0,-1);
	return 0;
}

4.牌型种数

小明被劫持到X赌城,被迫与其他3人玩牌。 一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。 这时,小明脑子里突然冒出一个问题: 如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

答案:3598180

分析:

我从第1种牌开始走,选i张(0<=i<=4),再去下一种牌的面前……,将第一种牌当成迷宫的入口,最后一种牌当成是迷宫的出口,到了迷宫的出口,如果此时手中的牌刚好是13张,就是一个方案

代码: 

#include
using namespace std;
int ans;
void dfs(int cnt,int sum){//cnt代表我走到第几点处了,sum表示我已经拿了几张牌了 
	if(cnt &

你可能感兴趣的:(dfs,bfs,算法)