洛谷P1464_Function 記憶化搜索
阿新 • • 發佈:2019-02-07
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 記憶化搜索