有些時候樸素深搜會出現超時狀況,因此誕生出一種記憶化搜索的dfs,其實它也是dfs,只不過在dfs的過程當中,添加了賦值的過程,這個賦值的過程就叫作記憶。這裏面會根據一些題目來說解記憶化搜索。ios
#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"; }
3 3 1 1 3 2 3 4 1 1 1 4
是否是什麼狀況都適合使用記憶化搜索呢?確定不是!
今天在寫到絡谷的一道題【
[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;就產生了重複計算的問題。函數