例一:求到终点的路径条数

思路:

深搜的时候是从vis[1][1]开始搜的,第一次直搜到vis[n][n],然后返回的时候可以得到vis[n-1][n-2]那个点的路,当第二次搜到vi[n-1][n-2]这个点的时候就不用往下搜了, 直接加上在这个点的路。

代码:

lld dfs(int x, int y) {

         if (vis[x][y] != 0) return vis[x][y]; //如果改点已搜过,直接返回结果即可

         if (x == n && y == n) return 1;

         for (int i = 0; i < 4; ++i) {

                   int nx = x + go[i][0];

                   int ny = y + go[i][1];

                   if (maze[nx][ny] != -1 && dist[nx][ny] < dist[x][y]) {

                            vis[x][y] += dfs(nx, ny);

                   }

         }

         return vis[x][y];

}

若没有使用记忆优化:

void dfs(int x,int y){

    int sx,sy,i;

    if(x==n&&y==n){

        tot++;//tot记录能够到达终点的路的条数

        return;

    }

    for(i=2;i<4;i++){

        sx=x+dir[i][0],sy=y+dir[i][1];

        if(sx>n||sy>n) continue;

        if(dis[sx][sy]>=dis[x][y]) continue;

        dfs(sx,sy);

    }

}

例二:求不同的排列数

题意:用A~Z代替1~26,问一串数字有多少不同的译码种数。

关键:若下一位不为0,本位可以拆分出来则 ret += dfs(x + 1);。若本位和下一位不超过26,且再后面的一位不为0,则这两位可以拆分出来则 ret += dfs(x + 2);。

代码:

lld dfs(int s, int e) {

         if (s >= e) return 1;

         if (dp[s] > 0) return dp[s];

         int t1 = str[s] - '0';

         int t2 = str[s + 1] - '0';

         if (t2 != 0) dp[s] += dfs(s + 1, e);

         if (t1 * 10 + t2 <= 26 && str[s + 2] != '0') //只剩最后两位的时候可以再计算一次

                   dp[s] += dfs(s + 2, e);

         return dp[s];

}

练习:

 

师弟