经典算法详解——状态压缩 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
相关推荐
垆边人似月.4 小时前
华为题:敏感词替换
算法
0+1115 小时前
算法 --哈希表
数据结构·算法·散列表
Interview Aid1125 小时前
Stripe VO 面经汇总:5 轮面试题目与考察重点
算法
EEET智选5 小时前
科技晨间速报 | AI 安全警钟、开源新模型与苹果智能家居
人工智能·科技·算法·机器学习·ai
挖掘狂人5 小时前
哈希算法:一根看不见的 "指纹",如何撑起整个互联网
算法·程序员·掘金技术征文
鶴哥只手遮天6 小时前
ecRad 1.5.0 算法原理详解
算法·开源
不会就选b6 小时前
算法日常・每日刷题--<动态规划>22
算法·动态规划
释厄6236 小时前
字画同体论——字即画·几何即字·漫画与小说=文本层
人工智能·算法
沫璃染墨6 小时前
从零入门数据结构与算法(一):复杂度分析——从算法效率到时间与空间复杂度
c语言·开发语言·数据结构·笔记·算法·飞书
熊猫钓鱼>_>7 小时前
面试出现 606 次的第 K 大,被拆成三个问题问
算法·面试·职场和发展·校招·面经·oj·ai生成