记忆化搜索(DFS)

记忆化搜索

记忆化搜索也是⼀种剪枝策略。

通过⼀个"备忘录",记录第⼀次搜索到的结果,当下⼀次搜索到这个状态时,直接在"备忘录"⾥⾯找结果。

记忆化搜索,有时也叫动态规划。

1.力扣斐波那契数


解题思路

斐波那契数从0到1开始后的数为前两项的和

可以看到在递归中有很多重复的问题

我们可以剪枝通过记忆化搜索,我们把每个已知答案存放,只要后续再碰到相同的问题就可以通过存放答案数组搜索无需再次递归。
如何实现记忆化搜索

1.创建备忘录

2.每次递归返回时先存放到备忘录中

3.递归时先查备忘录

代码

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 31;
int f[N];
int n;

int dfs(int n)
{
	//先查备忘录
	if (n == 0)return 0;
	if (n == 1)return 1;
	if (f[n]!=-1)return f[n];
	//先放到备忘录再返回
	return f[n] = dfs(n - 1) + dfs(n - 2);

}

int main()
{
	memset(f, -1, sizeof f); // 先初始化成⼀定不会存在的值 
	cin >> n;
	dfs(n);
	cout << f[n];
	return 0;
}

2.P1464 [PacNW 1999] Function



解题思路

根据题中要求遍历,但是一定会超时

所以可以利用记忆化搜索剪枝。因为递归中有重复问题

代码

cpp 复制代码
#include<iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 21;
LL f[N][N][N];
LL a, b, c;

LL dfs(LL a, LL b, LL c)
{
	if (a <= 0 || b <= 0 || c <= 0)return 1;
	if (a > 20 || b > 20 || c > 20)return dfs(20, 20, 20);
	if (f[a][b][c])return f[a][b][c];
	if (a < b && b < c)return f[a][b][c] = dfs(a, b, c - 1) + dfs(a, b - 1, c - 1) - dfs(a, b - 1, c);
	else return f[a][b][c] = dfs(a - 1, b, c) + dfs(a - 1, b - 1, c) + dfs(a - 1, b, c - 1) - dfs(a - 1, b - 1, c - 1);

}

int main()
{
	while (cin >> a >> b >> c)
	{
		if (a == -1 && b == -1 && c == -1)break;
		
		printf("w(%lld, %lld, %lld) = %lld\n", a, b, c, dfs(a, b, c));
	}
	return 0;
}

3.P5635 【CSGRound1】天下第一



解题思路

按照题中思路递归,途中可能碰到相同的问题,所以可以用记忆化搜索

利用数组结果输出,可以用字符数组,所占空间小

记忆化搜索的核心思想就是空间换时间:

通过备忘录数组存储已计算的子问题答案,避免重复递归,大幅降低时间复杂度,代价是占用少量额外存储空间。

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e4+10;
char f[N][N];

int T, p;
int a, b;

char dfs(int a, int b)
{
	if (f[a][b])return f[a][b];
	if (a == 0) return '1';
	if (b == 0) return '2';
	f[a][b] = '3';
	return f[a][b] = dfs((a + b) % p, (a + b + b) % p);
	
}

int main()
{
	cin >> T >> p;
	while (T--)
	{
		cin >> a >> b;
		char k = dfs(a, b);
		if (k == '1')
		{
			cout << 1 << endl;
		}
		else if (k == '2')
		{
			cout << 2 << endl;
		}
		else
		{
			cout << "error" << endl;
		}
	}
	return 0;
}

4.P1434 [SHOI2002] 滑雪



解题思路
方向 DFS 是逐点计算、逐方向试探;

一次 dfs 只算一个点的最优解;

整张图必须遍历所有点

代码

cpp 复制代码
#include<iostream>
using namespace std;
const int N = 1e3+10;
int f[N][N];
int k[N][N];
int dx[] = { 0,0,-1,1 };
int dy[] = { 1,-1,0,0 };
int n, m;


int dfs(int x, int y)
{
	//记忆化搜索
	if (f[x][y]) return f[x][y];

	int len = 1;
	for (int i = 0; i < 4; i++)
	{
		int a = x + dx[i]; int b = y + dy[i];
		//可行性剪枝
		if (a<1 || a>n || b<1 || b>m || k[x][y]<=k[a][b])continue;
		
		len = max(dfs(a,b) + 1,len);	
	}
	return f[x][y] = len;

}

int main()
{
	cin >> n >> m;
	
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> k[i][j];
		}
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			dfs(i, j);
		}
	}
	

	int ret = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			ret = max(f[i][j], ret);
		}
	}
	cout << ret;
	return 0;
}
相关推荐
Old Uncle Tom4 小时前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
会编程的土豆4 小时前
洛谷题单入门1 顺序结构
数据结构·算法·golang
生信碱移4 小时前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
智者知已应修善业5 小时前
【51单片机中的打飞机设计】2023-8-25
c++·经验分享·笔记·算法·51单片机
智者知已应修善业7 小时前
【51单片机按键调节占空比3位数码管显示】2023-8-24
c++·经验分享·笔记·算法·51单片机
.5488 小时前
## Sorting(排序算法)
python·算法·排序算法
wuweijianlove8 小时前
算法的平均复杂度建模与性能回归分析的技术7
算法·数据挖掘·回归
子琦啊8 小时前
【算法复习】字符串 | 两个底层直觉,吃透高频题
linux·运维·算法
code_pgf9 小时前
Octo 算法详解-开源通用机器人策略模型技术报告
算法·机器人·开源
嘻嘻哈哈樱桃10 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划