经典算法详解——状态压缩 DP

状态压缩 DP

到这里,我们知道了 S 到所有 M 的最短距离,也知道了 M 互相之间的最短距离,也知道了 M 到 T 的最短距离,这就是一个经典的状态压缩 DP 的模型了。

复杂度分析

注意事项

  • 由于本题的复杂度较高,使用 Python 等性能较差的语言实现时需要注意效率问题。
  • 本题边界情况较多,比如迷宫没有 M 、M 不可达等。

Python 实现

复制代码
import Queue
​class Solution(object):
    def minimalSteps(self, maze):
        """
        :type maze: List[str]
        :rtype: int
        """
        n = len(maze)
        m = len(maze[0])
        p = []
        #记录所有特殊点
        for i in range(n):
            for j in range(m):
                if maze[i][j] in ['S','T','M','O']:
                    p.append((i,j,maze[i][j]))
        dxs = [0,1,0,-1]
        dys = [1,0,-1,0]
        def bfs(x, y):
            q = Queue.Queue()
            q.put((x,y))
            dis = [[10000 for i in range(m)] for j in range(n)]
            dis[x][y] = 0
            while not q.empty():
                _ = q.get()
                x = _[0]; y = _[1]
                for dx, dy in zip(dxs, dys):
                    nx = x + dx; ny = y + dy
                    if nx < 0 or nx == n or ny < 0 or ny == m: continue
                    if maze[nx][ny] == '#': continue
                    if dis[nx][ny] > dis[x][y] + 1:
                        dis[nx][ny] = dis[x][y] + 1
                        q.put((nx,ny))
            res = []
            for i, j, _ in p:
                res.append(dis[i][j])
            return res
        #计算特殊点之间的最短距离
        tag = {}
        dis = []
        for idx, (i, j, t) in enumerate(p):
            dis.append(bfs(i, j))
            if not t in tag: tag[t] = []
            tag[t].append(idx)
        sidx = tag['S'][0]
        tidx = tag['T'][0]
        
        #特殊处理 M 不存在的情况
        if not 'M' in tag:
            ans = dis[sidx][tidx]
            if ans == 10000:
                ans = -1
            return ans
        
        #计算 S 到所有 M 点之间的最短距离
        Mnum = len(tag['M'])
        Onum = len(tag['O'])
        dp = [[10000 for i in range(Mnum)] for i in range(1<<Mnum)]
        for i in range(Mnum):
            midx = tag['M'][i]
            s = 1 << i 
            for j in range(Onum):
                oidx = tag['O'][j]
                dp[s][i] = min(dp[s][i], dis[sidx][oidx] + dis[oidx][midx])
    # 预处理 M 点之间的最短距离
        Mdis = [[10000 for i in range(Mnum)] for j in range(Mnum)]
        for i in range(Mnum):
            midx1= tag['M'][i]
            for j in range(Mnum):
                midx2 = tag['M'][j]
                for k in range(Onum):
                    oidx = tag['O'][k]
                    Mdis[i][j] = min(Mdis[i][j], dis[midx1][oidx] + dis[oidx][midx2])
                    
    #状态压缩DP
        for s in range(1<<Mnum):
            for j in range(Mnum):
                if s & (1<<j) == 0: continue
                for k in range(Mnum):
                    if s & (1<<k) != 0: continue
                    ns = s | (1<<k)
                    dp[ns][k] = min(dp[ns][k], dp[s][j] + Mdis[j][k])
        
        # 统计结果
        ans = 10000
        fs = (1<<Mnum) - 1
        for j in range(Mnum):
            midx = tag['M'][j]
            ans = min(ans, dp[fs][j] + dis[midx][tidx])
        if ans == 10000: ans = -1
        return ans
相关推荐
地平线开发者13 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮13 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者14 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考14 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx17 小时前
CART决策树基本原理
算法·机器学习
Wect18 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱18 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
Gorway1 天前
解析残差网络 (ResNet)
算法
拖拉斯旋风1 天前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect1 天前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript