hdoj1078(介绍记忆化搜索及其模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078

思路:

这是一道典型的记忆化搜索模板题。

先介绍记忆化搜索,本质是搜索+DP。

一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,以后再次遇到这个状态的时候,就不必重新求解了。这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。

记忆化搜索(Memory Search),其实还是用递归函数实现的,通常函数名依然叫做dfs。核心语句就是那两部分关键的语句块:
        1.函数一开始的判断出口:if(搜索过) return 数组中的值。因为这里涉及到是否搜索过,所以一般将数组初始化为-1。
        2.函数的递归前进语句:return fib[i]=fib[i-1]+fib[i-2];(没有具体的例子实在不好说了,所以这里用fib数列来做演示)。
这样就做到了数组的每个值只计算了一次,不会有多余的时间消耗。

下面就这道题来讲记忆化搜索基本模板,用dp[i][j]表示从(i,j)出发吃到的cheese最多的值,用(x,y)表示其邻点,则:

dp[i][j]=max(dp[i][j],a[i][j]+dp[x][y])(满足a[x][y]>a[i][j]时)。在这个递推式中,如果dp[i][j]被计算过一次,其值就是最终值,不用再计算。但是如果使用一般的dfs,则会出现大量重复计算一个值的情况,必然会超时。所以采用记忆化搜索,在递推过程中如果一个值被计算过(>=0),直接返回即可,否则计算其最终值并赋给它。也可以使用DP做这道题,但是要先排序,按照顺序来DP,但比较麻烦。而记忆化搜索则简洁自然许多,其实质当然就是DP。

详见代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,k;
 5 int a[105][105],dp[105][105];
 6 int go[4][2]={-1,0,0,1,1,0,0,-1};
 7 
 8 int dfs(int x,int y){
 9     if(dp[x][y]>=0) return dp[x][y];
10     dp[x][y]=a[x][y];
11     for(int i=0;i<4;++i)
12         for(int j=1;j<=k;++j){
13             int xx=x+j*go[i][0],yy=y+j*go[i][1];
14             if(xx>=0&&xx<n&&yy>=0&&yy<n&&a[xx][yy]>a[x][y])
15                 dp[x][y]=max(dfs(xx,yy)+a[x][y],dp[x][y]);
16         }
17     return dp[x][y];
18 }
19 
20 int main(){
21     while(~scanf("%d%d",&n,&k)&&n!=-1){
22         for(int i=0;i<n;++i)
23             for(int j=0;j<n;++j)
24                 scanf("%d",&a[i][j]);
25         memset(dp,-1,sizeof(dp));
26         printf("%d\n",dfs(0,0));
27     }
28     return 0;
29 }

猜你喜欢

转载自www.cnblogs.com/FrankChen831X/p/10434649.html