题目:原题链接(困难)

标签:动态规划

解法 时间复杂度 空间复杂度 执行用时
Ans 1 (Python) 520ms (96.20%)
Ans 2 (Python)
Ans 3 (Python)

解法一(贪心算法):

class Solution:def canMouseWin(self, grid: List[str], catJump: int, mouseJump: int) -> bool:def _is_valid(x, y):return 0 <= x < rows and 0 <= y < cols and grid[x][y] != "#"def _neighbours(x, y, d):"""计算可以一步到达的位置"""res = []for k in range(1, d + 1):if _is_valid(x - k, y):res.append((x - k, y))else:breakfor k in range(1, d + 1):if _is_valid(x + k, y):res.append((x + k, y))else:breakfor k in range(1, d + 1):if _is_valid(x, y - k):res.append((x, y - k))else:breakfor k in range(1, d + 1):if _is_valid(x, y + k):res.append((x, y + k))else:breakreturn resdef get_connect(x1, y1, x2, y2):"""计算(x1,y1)和(x2,y2)之间的连通性"""queue2 = collections.deque([(x1, y1)])visited2 = {(x1, y1)}while queue2:xx1, yy1 = queue2.popleft()if (xx1, yy1) == (x2, y2):return Truefor (xx2, yy2) in _neighbours(xx1, yy1, 1):if (xx2, yy2) not in visited2:visited2.add((xx2, yy2))queue2.append((xx2, yy2))return Falsedef get_abs_distance(p1, p2):return abs(p1[1] - p2[1]) + abs(p1[0] - p2[0])rows, cols = len(grid), len(grid[0])grid = [list(row) for row in grid]# ---------- 寻找猫、老鼠和食物的位置 ----------cat = (-1, -1)mouse = (-1, -1)food = (-1, -1)for i in range(rows):for j in range(cols):if grid[i][j] == "C":cat = (i, j)grid[i][j] = "."if grid[i][j] == "M":mouse = (i, j)grid[i][j] = "."if grid[i][j] == "F":food = (i, j)grid[i][j] = "."# ---------- 计算老鼠到达食物的唯一通道的拐角 ----------# 计算最短路径(唯一通道一定在最短路径上)visited = {mouse}queue = collections.deque([[mouse, [mouse]]])shortest_path = []while queue and not shortest_path:for _ in range(len(queue)):(i1, j1), path = queue.popleft()if (i1, j1) == food:shortest_path = pathbreakfor i2, j2 in _neighbours(i1, j1, 1):if (i2, j2) not in visited:visited.add((i2, j2))queue.append([(i2, j2), path + [(i2, j2)]])# 计算所有必经之路important_path = [mouse, food]for (i1, j1) in shortest_path:grid[i1][j1] = "#"if not get_connect(mouse[0], mouse[1], food[0], food[1]):important_path.append((i1, j1))grid[i1][j1] = "."# 计算所有必经之路拐点# 如果拐点是必经之路,那么拐点两边也一定是必经之路fortress = []for (i1, j1) in important_path:if (((i1 - 1, j1) in important_path and (i1, j1 - 1) in important_path) or((i1, j1 - 1) in important_path and (i1 + 1, j1) in important_path) or((i1 + 1, j1) in important_path and (i1, j1 + 1) in important_path) or((i1, j1 + 1) in important_path and (i1 - 1, j1) in important_path)):fortress.append((i1, j1))# print("堡垒:", fortress)# ---------- 计算各点之间的距离 ----------# O((NM)^2)distances_mouse = collections.defaultdict(dict)distances_cat = collections.defaultdict(dict)for i1 in range(rows):for j1 in range(cols):if grid[i1][j1] != "#":# 计算老鼠距离queue = collections.deque([(i1, j1)])visited = {(i1, j1)}step = 0while queue:for _ in range(len(queue)):i2, j2 = queue.popleft()distances_mouse[(i1, j1)][(i2, j2)] = stepfor i3, j3 in _neighbours(i2, j2, mouseJump):if (i3, j3) not in visited:visited.add((i3, j3))queue.append((i3, j3))step += 1# 计算猫距离queue = collections.deque([(i1, j1)])visited = {(i1, j1)}step = 0while queue:for _ in range(len(queue)):i2, j2 = queue.popleft()distances_cat[(i1, j1)][(i2, j2)] = stepfor i3, j3 in _neighbours(i2, j2, catJump):if (i3, j3) not in visited:visited.add((i3, j3))queue.append((i3, j3))step += 1# ---------- 处理获胜条件 ----------# 处理老鼠和食物不在同一个连通分支,则猫胜利if food not in distances_mouse[mouse]:return False# 如果猫和老鼠不在同一个连通分支,则老鼠胜利if mouse not in distances_cat[cat]:return True# 如果存在猫可以更快到达的必经之路拐点,则猫胜利(猫还剩一步就可以到达拐点时,老鼠已经不敢去拐点了)for (i, j) in fortress:if distances_cat[cat][(i, j)] <= distances_mouse[mouse][(i, j)]:return False# ---------- 逐步做出最优选择 ----------for _ in range(1000):# 如果猫可以比老鼠更快地到达终点,则猫胜利if math.ceil(distances_cat[cat][food]) < math.ceil(distances_mouse[mouse][food]):return False# 如果老鼠可以一步到达食物,则老鼠获胜if distances_mouse[mouse][food] <= 1:return True# 如果猫可以一步到达食物,则猫获胜if distances_cat[cat][food] <= 1:return False# 老鼠移动:最优策略为到不会被猫抓的距离食物最近的位置;如果步数相同,尽可能选择绝对距离更短的# 最优策略:# 1.不会被猫抓到# 2.尽可能离食物的步数更少# 3.如果距离食物步数相同,则选择绝对距离更短的# 4.如果绝对距离也相同,则选择距离猫(猫的步数)更远的位置# 5.如果距离猫的步数也相同,则选择距离猫的绝对距离更远的位置mouse_choice = (-1, -1)for (i, j), distance in distances_mouse[mouse].items():if distance > 1:continueif distances_cat[(i, j)][cat] <= 1:  # 1.不会被猫抓到continueif mouse_choice == (-1, -1):mouse_choice = (i, j)elif distances_mouse[mouse_choice][food] > distances_mouse[(i, j)][food]:  # 2.尽可能离食物的步数更少mouse_choice = (i, j)elif distances_mouse[mouse_choice][food] == distances_mouse[(i, j)][food]:if get_abs_distance(mouse_choice, food) > get_abs_distance((i, j), food):  # 3.如果距离食物步数相同,则选择绝对距离更短的mouse_choice = (i, j)elif distances_cat[cat][mouse_choice] < distances_cat[cat][(i, j)]:  # 4.如果绝对距离也相同,则选择距离猫(猫的步数)更远的位置mouse_choice = (i, j)elif distances_cat[cat][mouse_choice] == distances_cat[cat][(i, j)]:# 5.如果距离猫的步数也相同,则选择距离猫的绝对距离更远的位置if get_abs_distance(cat, mouse_choice) < get_abs_distance(cat, (i, j)):mouse_choice = (i, j)# 如果老鼠无法逃脱猫的追踪,则猫胜利if mouse_choice == (-1, -1):return False# 猫移动:最优策略为走向最近的必经之路拐点或食物点;如果步数相同,尽可能选择绝对距离更短的cat_choice = (-1, -1)for (i, j), distance in distances_cat[cat].items():if distance > 1:continueif (cat_choice == (-1, -1) ordistances_cat[cat_choice][food] > distances_cat[(i, j)][food] or(distances_cat[cat_choice][food] == distances_cat[(i, j)][food] andget_abs_distance(cat_choice, food) > get_abs_distance((i, j), food))):cat_choice = (i, j)mouse = mouse_choicecat = cat_choice# print("老鼠:", mouse, "猫:", cat)return False

LeetCode题解(1728):猫和老鼠II(Python)相关推荐

  1. LeetCode 142. 环形链表 II - Python 快慢指针法+详解

    题目 142. 环形链表 II 难度中等761 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的 ...

  2. LeetCode题解(1079):活字印刷(Python)

    题目:原题链接(中等) 标签:回溯算法 解法 时间复杂度 空间复杂度 执行用时 Ans 1 (Python) O(N!)O(N!)O(N!) O(N!)O(N!)O(N!) 136ms (43.48% ...

  3. LeetCode 213 House Robber II Python

    题意:你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金.这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的.同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的 ...

  4. Leetcode 534打劫房屋II python

    描述 在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的.每个房子都存放着特定金额的钱.你面临的唯一约束条件是:相邻 ...

  5. [H博弈论] lc1728. 猫和老鼠 II(博弈论+记忆化搜索+周赛224_4)

    文章目录 1. 题目来源 2. 题目解析 1. 题目来源 链接:1728. 猫和老鼠 II 2. 题目解析 棋盘类博弈论问题大多数采用记忆化搜索来进行优化.有效的状态空间没那么多,大多数都 break ...

  6. leetcode题解132-分割回文串 II

    问题描述 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文. 返回符合要求的 最少分割次数 . 示例 1: 输入:s = "aab" 输出:1 解释:只需一次分割 ...

  7. LeetCode 319. Bulb Switcher--C++,java,python 1行解法--数学题

    LeetCode 319. Bulb Switcher–C++,java,python 1行解法 LeetCode题解专栏:LeetCode题解 LeetCode 所有题目总结:LeetCode 所有 ...

  8. PHP版Leetcode题解开始随缘更新

    2019独角兽企业重金招聘Python工程师标准>>> PHP版Leetcode题解 我叫skys215,是一名bug工程师. 我接触编程的时间比较早,但是因为我数学不好加上比较懒, ...

  9. 32位有符号整数_008. 字符串转换整数 (atoi) | Leetcode题解

    点击上方"蓝色字体",选择"设为星标" 每天复习一道面试题,轻松拿大厂Offer~ 题目描述: 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先 ...

最新文章

  1. GraphPad Prism —— 简单又好用的生物数据统计绘图软件
  2. 谷歌对Deepfake亮剑:打造鉴假新工具,帮助媒体识别AI造假
  3. 每隔k次反转一次 链表_leetcode 25 K个一组翻转链表(c++)
  4. HTML学习笔记(三)样式CSS
  5. 灯光插件_Light Kit Pro 3灯光插件
  6. 【重复制造精讲】2、主数据介绍
  7. Bootstrap的全局css样式部分
  8. 小米组织架构再调整:手机部成立参谋部 朱磊出任参谋长
  9. android强制停止运行,如何在android中单击强制停止时运行服务
  10. git删除远程仓库的文件或目录
  11. mongoDB 基础指令
  12. 数码数字字体_国产太强!50包邮买到1000倍数码显微镜,让混用屏幕无所遁形
  13. “三区三线”永久基本农田划定实用工具
  14. 关于intelCPU缓存行,以及伪共享问题
  15. HomeKit 开发指南(中文版)
  16. 浅谈股价预测模型:分类树算法
  17. torch.Tensor.requires_grad_(requires_grad=True)的使用说明
  18. 登入拼多多显示服务器请求失败,拼多多商家后台登录打不开?
  19. SAP FICO 定义成本组件结构
  20. 数字同步网络时钟系统设计方案

热门文章

  1. cannon的英文名_Cannon[坎农]英文名的中文翻译意思、发音、来源及流行趋势-千代英文名...
  2. 直流电源和直流电子负载
  3. 众享比特荣登2020第六届中国最具投资价值公司百强榜
  4. Latex 三线表格
  5. Unity 动态生成球体模型
  6. 用双重for循环做9*9乘法表
  7. js方------将字符串转换成算术表达式,并计算出结果,例如(‘92-4*5/3‘)
  8. python开发的软件sparrow-自制编程语言:基于C语言 PDF 全书影印版
  9. PHP的学习笔记 (php的基础语法)
  10. 谷歌插件reres的使用,js文件替换神器