【力扣每日一题 0804】LEETCODE 980. 不同路径III (记忆化搜索 状态压缩)

引言

二维网格,一个起点一个终点,若干个障碍点,其余为空点,要求给出从起点到终点的所有不经过障碍点、不经过重复点、经过所有空点的路径总数。

例题

【LEETCODE 980】

算法描述

常规的做法是DFS,上下左右四个方向,回溯是否重复访问,并且记录一下经过的空点总数,最后判断一下是否可以计入答案。
改进的做法是,观察到本题的二维网格大小很小,可以状态压缩。状态由两部分组成,一部分为目前已经过的点,另一部分为当前点在哪个坐标。然后根据状态的值记忆化搜索即可。
由于本题的重复的情况并不多,所以改进版做法的实际用时可能更长,但是有必要学习一下状态压缩的写法。

代码实现

class Solution {
public:
    int dx[4] = {-1, 0, 1, 0}, 
        dy[4] = {0, -1, 0, 1};
    unsigned int st = 0; //状态
    int ans = 0;
    int n, m, nm;
    unordered_map<int, int> sta_val;

    int uniquePathsIII(vector<vector<int>>& a) {
        function<int(int, int)> get_xy = [=](int x, int y) -> int {
            return x * m + y;
        };

        int stai, staj;
        unsigned int full_st;
        n = a.size();
        m = a[0].size();
        full_st = (1 << n * m) - 1;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (a[i][j] == 1) {
                    stai = i;
                    staj = j;
                    st |= 1 << get_xy(i, j);
                } else if (a[i][j] == -1) {
                    st |= 1 << get_xy(i, j);
                }
            }
        }

        function<int(int, int, int)> dfs = [&](int x, int y, int st) -> int {
            if (a[x][y] == 2) {
                if (st == full_st)
                    return 1;
                return 0;
            }
            int ret = 0;
            int p = get_xy(x, y);
            int status = (p << n*m) | st;
            if (sta_val.count(status)) {
                return sta_val[status];
            }
            for (int i = 0; i < 4; i++) {
                int tx, ty;
                tx = x + dx[i];
                ty = y + dy[i];
                if (tx<0 || tx>=n || ty<0 || ty>=m || st>>get_xy(tx, ty)&1 || a[tx][ty]==-1) {
                    continue;
                }
                ret += dfs(tx, ty, st|(1<<get_xy(tx, ty)));
            }
            return sta_val[status] = ret;
        };

        return dfs(stai, staj, st);
    }

    
};

关键词

力扣 每日一题 不同路径III 980 DFS 记忆化搜索 状态压缩

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值