記憶化搜索


今天的時間較短,沒有刷很多的題,只刷了一道記憶化搜索的題目,還調試了半天(就是因為輸出沒有換行TwT)。但就是這道題讓我把新手村A掉啦~\(≧▽≦)/~

記憶化搜索

·記憶化搜索是啥?

  所謂記憶化搜索,就是讓程序實現自動記憶已經搜索過的東西,這樣如果再次搜到這個東西,就可以直接調用了。

·記憶化搜索與dp的不同點:

  dp需要對每個狀態進行遍歷,而記憶化搜索則可以排除無用狀態。更重要的是,記憶化搜索還可以剪枝,這樣一來,就大大降低了空間復雜度。

·接下來就是我調了半天的題了:

  相信大家一定都做過,這道題就是大名鼎鼎的“function”。

  題目描述: 

    定義一個遞歸函數w(a,b,c),遞歸條件是這樣的:

    (1)如果a \le 0a0 or b \le 0b0 or c \le 0c0就返回值11.

    (2)如果a>20a>20 or b>20b>20 or c>20c>20就返回w(20,20,20)w(20,20,20)

    (3)如果a<ba<b並且b<cb<c 就返回w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)w(a,b,c1)+w(a,b1,c1)w(a,b1,c)

    (4)其它的情況就返回w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)w(a1,b,c)+w(a1,b1,c)+w(a1,b,c1)w(a1,b1,c1)

    這是一個簡單的遞歸函數,但是實現起來可能會有些問題,比如當a、b、c都是15的時候調用的次數非常多,必須想一個辦法!

  題目分析:

    這個辦法就是“記憶化搜索”。根據(2)可以初步確定要將20以內的狀態存下來,這樣一來,每次遍歷到這個狀態時,就不用再去計算,直接返回已經存好的狀態就可以啦!

  代碼實現:

 1 #include<cstdio>
 2 #include<iostream>
 3 #define ll long long
 4   
 5 using namespace std;  6   
 7 ll a,b,c;  8 ll ans[30][30][30];  9 
10 ll function(ll x,ll y,ll z) 11 { 12      if(x<=0||y<=0||z<=0) return 1; 13      if(x>20||y>20||z>20) return function(20,20,20); 14      if(ans[x][y][z]!=0) return ans[x][y][z];//如果這個情況已經被存在了ans數組中,那么就直接返回此狀態下數組的值
15      if(x<y&&y<z) ans[x][y][z]=function(x,y,z-1)+function(x,y-1,z-1)-function(x,y-1,z); 16      else return ans[x][y][z]=function(x-1,y,z)+function(x-1,y-1,z)+function(x-1,y,z-1)-function(x-1,y-1,z-1);//將各種狀態存到ans數組中
17      return ans[x][y][z]; 18 } 19  
20 int main() 21 { 22     while(1)//如果不在循環中加上return 0,就會一直不停的讀下去
23  { 24         scanf("%lld%lld%lld",&a,&b,&c); 25         if(a==-1&&b==-1&&c==-1) return 0;讀到-1,-1,-1時直接結束程序 26         printf("w(%lld, %lld, %lld) = ",a,b,c); 27         if(a>20) a=21; 28         if(b>20) b=21; 29         if(c>20) c=21;//減少不必要的計算
30         printf("%lld\n",function(a,b,c)); 31  } 32 }

 ·總結:

  記憶化搜索本質上是一種dp思想,但是又比dp快一點的算法,可以運用在在考試和平時做題時。  

  對了,還有一件事,一定要看好輸出格式,比如這道題我就沒有換行,導致WA了三次TwT。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM