习题9-1(最长滑雪路径)【深搜dfs】+【记忆化搜索】

习题9-1

【UVa 10285】longest Run on a Snowboard(最长滑雪路径)

题目大意:

在一个R*C(R,C<=100)的整数矩阵上找一条高度严格递减的最长路。起点任意,但每次只能沿着上下左右4个方向之一走一格,并且不能走出矩阵外。如图所示,最长路就是按照高度25,24,23,…,2,1这样走,长度为25。矩阵中的数均为0~100.
图:

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

思路:

可以看到样例中的最长路就是顺时针螺旋向中心前进,这个过程应该很容易在脑海里模拟吧,于是我们现在可以推出一个深搜的过程(即假设每个整数为一个节点,从各个节点出发,向着每个相对于自身小的方向尽可能深入地搜索),访问过某个节点后,进行记忆化操作(即使用向下节点的最值返回值更新设置的f数组,使脱离未访问状态,同时也是记录结果),之后再次访问时可直接调用此数组对应下标的值,避免重复访问(此处应满足无后效性),这样一直到以最后一个节点为起点搜索完,循环遍历一遍f数组,得到的最大值即为答案。

tips:在深搜时对于方向的选择使用了一个从紫书上学到的小技巧,即单层循环用dir[5]={-1,0,1,0,-1},对于八个方向的,可以双层循环dir[3]={-1,0,1},可以省一些功夫复制粘贴:-D

代码:

#include
#include
using namespace std;
#define N 1000

int T;string name; 
int m,n,map[N][N],ans,dp[N][N],dir[5]={-1,0,1,0,-1};

void init(){
    cin>>m>>n;
    memset(dp,0,sizeof(dp));
    ans=-1;
    for(int i=0;i<=m+1;i++)
        for(int j=0;j<=n+1;j++)
            map[i][j]=150;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            cin>>map[i][j];
}

int dfs(int a,int b){
    if(dp[a][b]){
        return dp[a][b];
    }

    int p,mp=0;
    for(int i=0;i<4;i++){
        if(map[a+dir[i]][b+dir[i+1]]<map[a][b]){
            p=dfs(a+dir[i],b+dir[i+1]);
            if(p>mp) mp=p;
        }
    }

    return dp[a][b]=mp+1;
}

int findmax(){
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            if(ansint main(){
    cin>>T;
    while(T--){
        cin>>name;
        init();
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                dfs(i,j);
            }
        }
        findmax();
        cout<": "<return 0;
}

后记:

学动态规划做的第一题,因为一直在看那些动不动就开多维数组所以一开始看到题目是懵逼的(ーー゛)关键脑子没调回来,瞄了一眼题解,哦懂了╮(╯▽╰)╭,然后就一下AC了,生活总是这么美好多好(  ̄ー ̄)人(^▽^ )

你可能感兴趣的:(紫书第九章)