记忆化搜索
好久没写了...
先摘一段百度的关于记忆化搜索的定义和比较:
记忆化搜索:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
----------------------------------------------------------------------------------------------------------------------
So,怎么得到的呢?用下面的例子:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
把1作为起点,假设一开始找到的路是这样,找到25找不到了,就返回1,不断加一,最后生成的dp数组如下:
5 4 3 0 0
0 0 2 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
当然,还没结束,第二条假设找到了这样的:1->2->17->18->25:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
由于18已经被dp[3][2]记录成2了,所以直接返回2的值,这一路就不用继续搜下去到25了,
这就是一个剪枝的过程模拟,有点乱啊...
-----------------------------------------------------------------------------------------------------
其实之前感觉这样直接返回那个位置dp会不会得不到最优,其实不会的,就算当前直接返回的dp
的不是最优,但是也是记录了这一路深搜的结果;如果有更优的,那么可以把它的dp值更新成新
的值,通过一个判断大小就可以了,最后看代码:
// poj 1008. 滑雪 // 简单dp 一点都不简单啊 // 实际上说是记忆化搜索更合适 // dp[i][j]为到(i,j)的最长距离或者从(i,j)出发的最长距离都行 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 105; int n, m; int dp[N][N]; int graph[N][N]; int move_x[] = {0, 0, 1, -1}; int move_y[] = {1, -1, 0, 0}; int dfs(int i, int j) { if(dp[i][j]) return dp[i][j]; dp[i][j] = 1; for(int k=0; k<4; k++) { int tx = i + move_x[k]; int ty = j + move_y[k]; if(tx >= 1 && tx <= n && ty >=1 && ty <= m) { if(graph[tx][ty] > graph[i][j] && dp[i][j] < dfs(tx, ty) + 1) { dp[i][j] = dp[tx][ty] + 1; } } } return dp[i][j]; } int main() { while(scanf("%d%d", &n, &m) != EOF) { memset(dp, 0 ,sizeof(dp)); int maxn = -1; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d", &graph[i][j]); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { int len = dfs(i, j); if(maxn < len) maxn = len; } printf("%d\n", maxn); } return 0; }