首页 > 其他分享 >【学习笔记】记忆化搜索

【学习笔记】记忆化搜索

时间:2023-08-01 16:47:28浏览次数:29  
标签:搜索 le int pos 笔记 记忆 草药 maxn

记忆化搜索

目录

oiwiki:记忆化搜索

建议搭配食用。

前置知识:

  • 深度优先搜索 DFS

概念:

搜索通常通过递归来实现,但是递归过程中往往有很多结果被重复计算,因此降低了搜索的效率。

因此记忆化搜索就是再递归的过程中记录已经遍历过的状态与结果,用到的时候再直接取出,避免了重复运算。

实现:

oiwiki 讲的很好,但是我要再赘述一遍:

[NOIP2005] 采药

[NOIP2005 普及组] 采药

题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 \(2\) 个整数 \(T\)(\(1 \le T \le 1000\))和 \(M\)(\(1 \le M \le 100\)),用一个空格隔开,\(T\) 代表总共能够用来采药的时间,\(M\) 代表山洞里的草药的数目。

接下来的 \(M\) 行每行包括两个在 \(1\) 到 \(100\) 之间(包括 \(1\) 和 \(100\))的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

样例 #1

样例输入 #1

70 3
71 100
69 1
1 2

样例输出 #1

3

提示

【数据范围】

  • 对于 \(30\%\) 的数据,\(M \le 10\);
  • 对于全部的数据,\(M \le 100\)。

【题目来源】

NOIP 2005 普及组第三题。

这道题其实我记得我是用背包 dp 做的,但是今天我们先来进行一个朴素的 DFS 做法。

代码写了注释了,学过 dfs 都能懂

朴素搜索
#include<bits/stdc++.h>
using namespace std;

typedef long double llf;
typedef long long intx;
const int maxn=105;

int n,t;
//总共n株草药,总时间为t 
int cost[maxn],val[maxn];
//cost是草药的花费时间,val是权值 
int ans;

void input(){
	scanf("%d %d",&t,&n);
	for(int i=1;i<=n;++i){
		scanf("%d %d",&cost[i],&val[i]);
	} 	
}

void dfs(int pos,int lost,int sval){
//pos记录当前准备选第几个物品,lost表示剩下的时间,sval表示已获得的价值
	if(lost<0)	return;
	//不剩时间了没有继续的必要 
	if(pos==n+1){
	//草药已经摘到最后一株,更新答案后返回 
	 	ans=max(ans,sval); 
	 	return;
	} 
	dfs(pos+1,lost,sval);
	dfs(pos+1,lost-cost[pos],sval+val[pos]);
	//选或者不选 
}

int main(){
	input();
	dfs(1,t,0);
	printf("%d\n",ans); 
	return 0;
}

然后 T 啦!!

同一状态会被访问多次,比如我们把采草药叫做状态 \(1\),不采草药叫做 \(0\)。

(利用了状态压缩的思想解释被访问多次的状态,但是这道题由于 \(n\) 范围过大不适合状压 dp 来做)

对于 \(n==12\),状态 \(1\) \(0\) \(0\) \(1\) \(1\) \(1\) 来说,之后还有六个状态是未知的,但是这个状态会被重复走很多次。

具体想知道运行时间有多大差距可以看木偶Roy的运行结果对比

那么我们专门来为这个状态开一个数组 \(memo_{pos,lost}\) 表示记录的搜索返回值 \(sval\),再次访问的时候直接返回数值即可,这样也使得 dfs 省了一个参数 \(sval\)。

而对于初始化来讲,我们可以使其值为一个绝对不可能的值表示没有搜索到过(本题为 \(-1\))。

有代码实现:

记忆化搜索
#include<bits/stdc++.h>
using namespace std;

#define MYMIN -191981000
typedef long double llf;
typedef long long intx;
const int maxn=105,maxm=1005;

int n,t;
//总共n株草药,总时间为t 
int cost[maxn],val[maxn];
//cost是草药的花费时间,val是权值
int memo[maxn][maxm];
//记忆状态 
int ans;

void input(){
	scanf("%d %d",&t,&n);
	for(int i=1;i<=n;++i){
		scanf("%d %d",&cost[i],&val[i]);
	} 	
}

int dfs(int pos,int lost){
//pos记录当前准备选第几个物品,lost表示剩下的时间
	if(memo[pos][lost]!=-1)	return memo[pos][lost];
	//如果已经访问过就直接返回 
	if(pos==n+1){
	//草药已经摘到最后一株
		return memo[pos][lost]=0;
	}
	int dfs1,dfs2=MYMIN;
	dfs1=dfs(pos+1,lost);
	//不采药
	if(lost>=cost[pos]){
	//如果还能继续采才有dfs2
		dfs2=dfs(pos+1,lost-cost[pos])+val[pos]; 
	} 
	return memo[pos][lost]=max(dfs1,dfs2);
	//将当前状态存下来,如果没有dfs2对结果无影响,因为dfs2的初始值是最小值 
}

int main(){
	memset(memo,-1,sizeof(memo));
	input();
	ans=dfs(1,t); 
	printf("%d\n",ans); 
	return 0;
}

对于这道题我们总结一下记忆化搜索的特点:

  • 不依靠外部变量 \(ans\) 记录,往往意味着函数具有返回值。

  • 因为答案是返回值,所以不成为函数的参数。

  • 对于一组参数,其返回值相同。

标签:搜索,le,int,pos,笔记,记忆,草药,maxn
From: https://www.cnblogs.com/sonnety-v0cali0d-kksk/p/17596911.html

相关文章

  • 最小割树 学习笔记
    问题描述给定一张图,求任意两点的最小割。要求跑\(n\)次最大流。做法暴力需要跑\(n^2\)次最大流,然而这样很浪费,因为求出\(u,v\)两点的最小割以后,我们还获得了至少一种最小割方案,可以通过这一方案获得更多信息。注意到假设通过最小割断开后,\(s,t\)所在集合分别为\(S,T......
  • 如何提交学习笔记到Github
    前提条件:已经注册好Github账号步骤:*登录Github账号后,点击“+”新建仓库,根据提示命名和初始化仓库*克隆仓库到本地`gitclone<仓库的URL>`*在仓库文件夹里修改和添加文件*提交变更 *`gitadd*` *`gitcommit-m"对变更的描述"`*推送到Github`gitpushoriginmain`......
  • 白日梦的Elasticsearch实战笔记,32个查询案例、15个聚合案例、7个查询优化技巧。
    目录一、导读二、福利:账号借用三、_searchapi搜索api3.1、什么是querystringsearch?3.2、什么是querydsl?3.3、干货!32个查询案例!四、聚合分析4.1、什么是聚合分析?4.2、干货!15个聚合分析案例五、7个查询优化技巧公众号、欢迎关注一、导读Hi!大家久等了!时隔10天,白日梦的Elasticsea......
  • 白日梦的Elasticsearch实战笔记,ES账号免费借用、32个查询案例、15个聚合案例、7个查询
    目录一、导读二、福利:账号借用三、_searchapi搜索api3.1、什么是querystringsearch?3.2、什么是querydsl?3.3、干货!32个查询案例!四、聚合分析4.1、什么是聚合分析?4.2、干货!15个聚合分析案例五、7个查询优化技巧欢迎关注一、导读Hi!大家久等了!时隔10天,白日梦的Elasticsearch笔记......
  • C++ Primer 学习笔记——第九章
    第9章顺序容器前言本章是对第三章——字符串、向量和数组的扩展延伸,在第三章我们对标准库的顺序容器有一定了解,那么学习完本章我们对顺序容器的知识将会更加完整。标准库定义了几种关联容器,关联容器中元素的位置由元素相关联的关键字值决定。我们将在本章对关联容器做一定了解......
  • 8.1 day9搜索
    0+50+100+0=150第一题本地没re,交上去re了,发现是函数int没returnO2导致的,但是本地也开了O2,没有问题T1中缀转后缀,然后全排列T2枚举每一位是否填1,倒序开搜+小剪枝即可,最科学的是一种背包的剪枝,和我最终提交代码很像,但是我的优化还不够T3ida,限制深度,个数可看成矩阵乘法T4正......
  • git学习笔记(十二):标签管理
    打标签,方便找。tag就是一个让人容易记住的有意义的名字,跟某个commit捆绑在一起。(就是一个指向commit的指针,原来的哈希表值太复杂了,不方便沟通,所以给了一种定制的简化版。)打标签切换到需要打标签的分支上,然后使用命令$gittagv1.0可以使用gittag查看所有标签。默认的标......
  • 分布式搜索 - 什么是倒排索引
    这个问题是近段时间被问的最多的,理清思路就更好理解了,下面贴出来,也配合表格辅助理解。其实很多搜索引擎都是基于倒排索引,比如luncene,solr以及elasticsearch正排索引 聊倒排搜索之前先来看看正排索引,正排其实就是数据库表,他通过id和数据进行关联,如下:我们可以通过搜索id,来获得......
  • PyTorch基础知识-新手笔记
    逐元素操作Tensor中也有逐元素操作,大部分的数学运算都属于逐元素操作,逐元素操作的输入与输出的形状相同。常见的逐元素操作可参考下表:abs/add:绝对值/加法addcdiv(t,t1,t2,value=1):t1与t2按元素除后,乘以value加t,即t+(t1/t2)*valueaddcmul(t,t1,t2,value=1):t1与t2按元素乘后,乘......
  • 系统架构设计师笔记第39期:数据架构规划与设计
    数据架构规划与设计是指在软件系统中规划和设计数据的组织结构、存储方式和访问方法,以满足系统需求和实现数据的有效管理和利用。在数据架构规划与设计中,通常包括以下几个关键方面:数据模型设计:数据模型是描述系统中数据的逻辑结构和关系的抽象表示。常见的数据模型包括层次模型、网......