記憶化搜索專題

記憶化搜索專題訓練

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;就產生了重複計算的問題。函數

相關文章
相關標籤/搜索