1. 程式人生 > >洛谷P1464_Function 記憶化搜索

洛谷P1464_Function 記憶化搜索

i++ sin cti include code span ons ace 自己

洛谷P1464_Function

本次隨筆專門討論記憶化搜索

記憶化搜索常常和dp+遞歸結合,用來解決重復冗余問題。目的是加快搜索效率,避免tle。但是在數據範圍較大的dp中使用會仍然有問題,比如爆棧(遞歸太深)

基本思路是通過一個記錄狀態的數組/記錄答案的數組,保存前一階段的狀態/結果,從而在後一階段的調用中直接獲得答案,而不是重新調用遞歸。

我的代碼:

其中註釋部分是AC代碼,而非註釋部分是另外一種更為簡便的記憶化方法

 1 #include<iostream>
 2 using namespace std;
 3 typedef long long ll;
 4 const int
N=1000; 5 int w[25][25][25]={{{}}}; 6 struct var{ 7 ll a; 8 ll b; 9 ll c; 10 }g[N]; 11 //記憶化搜索 12 int func(ll a,ll b,ll c){ 13 if(a<=0||b<=0||c<=0){ 14 return 1; 15 } 16 else if(a>20||b>20||c>20) return func(20,20,20); 17 else{ 18 if(w[a][b][c]>0
) return w[a][b][c]; 19 else if(a<b&&b<c){ 20 // w[a][b-1][c-1]=func(a,b-1,c-1); 21 // w[a][b][c-1]=func(a,b,c-1); 22 // w[a][b-1][c]=func(a,b-1,c); 23 w[a][b][c] = func(a,b-1,c-1)+func(a,b,c-1)-func(a,b-1,c); 24 // return w[a][b-1][c-1]+w[a][b][c-1]-w[a][b-1][c];
25 } 26 else{ 27 // w[a-1][b-1][c-1]=func(a-1,b-1,c-1); 28 // w[a-1][b][c-1]=func(a-1,b,c-1); 29 // w[a-1][b-1][c]=func(a-1,b-1,c); 30 // w[a-1][b][c]=func(a-1,b,c); 31 w[a][b][c]=func(a-1,b,c-1)+func(a-1,b-1,c)+func(a-1,b,c)-func(a-1,b-1,c-1); 32 // return w[a-1][b][c]+w[a-1][b-1][c]+w[a-1][b][c-1]-w[a-1][b-1][c-1]; 33 } 34 return w[a][b][c]; 35 } 36 } 37 int main(){ 38 w[0][0][0]=1; 39 int i; 40 for(i=0;;i++){ 41 cin >> g[i].a >> g[i].b >> g[i].c; 42 if(g[i].a==-1&&g[i].b==-1&&g[i].c==-1){ 43 break; 44 } 45 } 46 for(int k=0;k<i;k++){ 47 cout << "w(" << g[k].a << ", " << g[k].b << ", " << g[k].c << ") = " << func(g[k].a,g[k].b,g[k].c) << endl; 48 } 49 return 0; 50 }

其實註釋部分(我自己的記憶化方法)的本質就是非註釋部分。想想看,如果w[a][b][c]沒有被計算過,那麽肯定會在執行func(a,b,c)時給w[a][b][c]賦值,因此不必還單獨給func(a,b-1,c-1)之類的賦值了。

另外對於記憶化搜索其實還有個值得註意的,就是在一個表達式中涉及多個狀態數組值的問題,可以考慮先計算那個小的(也就是本來按順序就排列在前面的)

不過好像也沒有太大關系,主要自己覺得更順心一點。

洛谷P1464_Function 記憶化搜索