记忆化搜索专题

记忆化搜索专题训练

0.前言

有些时候朴素深搜会出现超时状况,因此诞生出一种记忆化搜索的dfs,其实它也是dfs,只不过在dfs的过程当中,添加了赋值的过程,这个赋值的过程就叫作记忆。这里面会根据一些题目来说解记忆化搜索。ios

1.样例分析

1.1 题目 络谷 P1434滑雪
1.2分析
  • 找出每一个坐标点 (x,y) 的最大滑雪距离,并为其赋值,若下次还搜到了这个点,这直接返回这个值,而不用再次搜索。
1.3代码
#include<iostream>

using namespace std;
const int maxN = 105;
int n,m;//行列 
int arr[maxN][maxN];//初始的二维序列
int dis[maxN][maxN];// dis[i][j]表示(i,j)可以滑行的最远距离

int getMax(int a,int b,int c,int d){//从4个整数中取最大值
	return max((max(a,b)),max(c,d) );
}

//计算(x,y)可以滑行的最远距离sum
//prior表示上一个数是多少 
int dfs(int x,int y,int prior){
	//1.若是越界 或者 高度达不到要求
	if(x<0 || x>=n || y<0 || y>=m || prior <= arr[x][y] ){
		return 0;
	}
	
	if(dis[x][y] != 0){//2.若是已经计算过,就不用再计算了,直接返回便可
		return dis[x][y]; 
	}
	
	prior = arr[x][y];	
	dis[x][y] =getMax(//3.返回四个中的最大值,并赋值给dis[x][y]
					dfs(x-1,y,prior),
					dfs(x,y+1,prior),
					dfs(x+1,y,prior),
					dfs(x,y-1,prior) )+1;
	
	//4.返回最后的计算结果(为main函数中的tempDis服务)
	return dis[x][y];
} 
 
int main(){
	cin >> n>> m;
	fill(dis[0],dis[0]+maxN*maxN,0);//初始化为0 
	int maxDis = 0;
	for(int i = 0;i<n;i++){
		for(int j = 0;j<m;j++){
			cin >> arr[i][j];			
		}
	}
			
	for(int i = 0;i<n;i++){
		for(int j = 0;j<m;j++){
			//(i,j) 
			int tempDis = dfs(i,j,9999);//深搜 
			if(maxDis < tempDis ){
				maxDis = tempDis;//深搜 
			}
		}
	}
	
	cout << maxDis<<"\n";
} 
1.4 测试用例:
3 3 
1 1 3
2 3 4
1 1 1
4

2.反例分析

是否是什么状况都适合使用记忆化搜索呢?确定不是!
今天在写到络谷的一道题【
[USACO08JAN]牛大赛Cow Contest 】时,想着是否是可使用记忆化搜索。举例以下。
输入样例:奶牛4战胜了2,2又战胜了1,5战胜了2 。
这样咱们就能够记录win[1]=0,win[2]=1,win[4]=2。等第搜索5时,发现2已经搜索过了,直接返回 win[2]+1 = 2 ,这样就算出来了win[5]=2。可是这样真的合适吗?就拿题中给出的测试用例:ide

5 5
4 3
4 2
3 2
1 2
2 5

这时记忆化搜索就行不通了,缘由是会 出现重复计算。
假设先计算奶牛2,发现奶牛2赛过的牛有1头(即win[2]=1)。
计算3时,2已经计算过了,直接返回win[2]+1 = 2;计算4时,由于4便可到2,又可到3,且他们都已经访问过了,因此有win[4] += (win[2]+1) = 3;,win[4] += (win[3]+1) =5;就产生了重复计算的问题。函数

相关文章
相关标签/搜索