[LeetCode] 913. Cat and Mouse 猫和老鼠
A game on an undirected graph is played by two players, Mouse and Cat, who alternate turns.
The graph is given as follows: graph[a]
is a list of all nodes b
such that ab
is an edge of the graph.
Mouse starts at node 1 and goes first, Cat starts at node 2 and goes second, and there is a Hole at node 0.
During each player's turn, they must travel along one edge of the graph that meets where they are. For example, if the Mouse is at node 1
, it must travel to any node in graph[1]
.
Additionally, it is not allowed for the Cat to travel to the Hole (node 0.)
Then, the game can end in 3 ways:
- If ever the Cat occupies the same node as the Mouse, the Cat wins.
- If ever the Mouse reaches the Hole, the Mouse wins.
- If ever a position is repeated (ie. the players are in the same position as a previous turn, and it is the same player's turn to move), the game is a draw.
Given a graph
, and assuming both players play optimally, return 1
if the game is won by Mouse, 2
if the game is won by Cat, and 0
if the game is a draw.
Example 1:
Input: [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
Output: 0
Explanation: 4---3---1
| |
2---5
\ /
0
Note:
3 <= graph.length <= 50
- It is guaranteed that
graph[1]
is non-empty. - It is guaranteed that
graph[2]
contains a non-zero element.
这道题是猫抓老鼠的问题,Tom and Jerry 都看过吧,小时候看着笑到肚子疼的一部动画片,真是经典中的经典。这道题在无向图上模仿了猫抓老鼠的这一个过程,老鼠位于结点1,猫位于结点2,老鼠的目标是逃回老鼠洞结点0,猫的目标是在老鼠进洞之前抓住它。这里假设猫和老鼠都不是沙雕,都会选择最优的策略。若老鼠能成功逃回洞里,则返回1;若猫能成功抓到老鼠,则返回2;若谁也不能达到目标,则表示平局,返回0。其实这道题的本质还是一个无向图的遍历问题,只不过现在有两个物体在遍历,比一般的图遍历要复杂一些。假设图中有n个结点,不论是猫还是老鼠,当各自走完了n个结点时还没有分出胜负,则表示平局,若一人走一步,则最多有 2n 步。这样的话每一个状态实际上是由三个因素组成的:当前步数,老鼠所在结点,和猫所在结点。这里可以用动态规划 Dynamic Programming 来解,使用一个三维的 dp 数组,其中 dp[t][x][y] 表示当前步数为t,老鼠在结点x,猫在结点y时最终会返回的值,均初始化为 -1。要求的其实是起始状态 dp[0][1][2] 的返回值,但没法一下子求出,这个起始状态实际上是要通过其他状态转移过来,就比如说是求二叉树最大深度的递归函数,虽然对根结点调用递归函数的返回值就是最大深度,但在函数遇到叶结点之前都无法得知深度。先来看一些终止状态,首先当老鼠到达洞口的时候,此时老鼠赢,返回值是1,即所有 dp[?][0][?] 状态的返回值都是1。其次,当猫和老鼠处于同一个位置时,表示猫抓到老鼠了,此时猫赢,返回值是2,即所有 dp[?][y][y] 状态的返回值都是2。最后,当走完了 2n 步还没有分出胜负的话,则是平局,直接返回0即可。
理清了上面的思路,其实代码就不难写了,这里使用递归的写法,在递归函中,首先判断步数是否到了 2n,是的话直接返回0;否则判断x和y是否相等,是的话当前状态赋值为2并返回;否则再判断x是否等于0,是的话当前状态赋值为1并返回。若当前状态的 dp 值不是 -1,则表示之前已经更新过了,不需要重复计算了,直接返回即可。否则就要来计算当前的 dp 值,先确定当前该谁走,只要判断t的奇偶即可,因为最开始步数0的时候是老鼠先走。若此时该老鼠走了,它能走的相邻结点可以在 graph 中找到,对于每一个可以到达的相邻结点,都调用递归函数,此时步数是 t+1,老鼠位置为相邻结点,猫的位置不变。若返回值是1,表示老鼠赢,则将当前状态赋值为1并返回;若返回状态是2,此时不能立马返回猫赢,因为老鼠可以不走这个结点;若返回值是0,表示老鼠走这个结点是有平局的机会,但老鼠还是要争取赢的机会,所以此时用一个 bool 变量标记下猫肯定赢不了,但此时也不能直接返回,因为 Jerry 一直要追寻赢的机会。直到遍历完了所有可能性,老鼠最终还是没有赢,则看下之前那个 bool 型变量 catWin,若为 true,则标记当前状态为2并返回,反之,则标记当前状态为0并返回。若此时该猫走了,基本跟老鼠的策略相同,它能走的相邻结点也可以在 graph 中找到,对于每一个可以到达的相邻结点,首先要判断是否为结点0(老鼠洞),因为猫是不能进洞的,所以要直接跳过这个结点。否则就调用递归函数,此时步数是 t+1,老鼠位置不变,猫的位置为相邻结点。若返回值是2,表示猫赢,则将当前状态赋值为2并返回;若返回状态是1,此时不能立马返回老鼠赢,因为猫可以不走这个结点;若返回值是0,表示猫走这个结点是有平局的机会,但猫还是要争取赢的机会,所以此时用一个 bool 变量标记下老鼠肯定赢不了,但此时也不能直接返回,因为 Tom 也一直要追寻赢的机会。直到遍历完了所有可能性,猫最终还是没有赢,则看下之前那个 bool 型变量 mouseWin,若为 true,则标记当前状态为1并返回,反之,则标记当前状态为0并返回,参见代码如下:
class Solution {
public:
int catMouseGame(vector<vector<int>>& graph) {
int n = graph.size();
vector<vector<vector<int>>> dp(2 * n, vector<vector<int>>(n, vector<int>(n, -1)));
return helper(graph, 0, 1, 2, dp);
}
int helper(vector<vector<int>>& graph, int t, int x, int y, vector<vector<vector<int>>>& dp) {
if (t == graph.size() * 2) return 0;
if (x == y) return dp[t][x][y] = 2;
if (x == 0) return dp[t][x][y] = 1;
if (dp[t][x][y] != -1) return dp[t][x][y];
bool mouseTurn = (t % 2 == 0);
if (mouseTurn) {
bool catWin = true;
for (int i = 0; i < graph[x].size(); ++i) {
int next = helper(graph, t + 1, graph[x][i], y, dp);
if (next == 1) return dp[t][x][y] = 1;
else if (next != 2) catWin = false;
}
if (catWin) return dp[t][x][y] = 2;
else return dp[t][x][y] = 0;
} else {
bool mouseWin = true;
for (int i = 0; i < graph[y].size(); ++i) {
if (graph[y][i] == 0) continue;
int next = helper(graph, t + 1, x, graph[y][i], dp);
if (next == 2) return dp[t][x][y] = 2;
else if (next != 1) mouseWin = false;
}
if (mouseWin) return dp[t][x][y] = 1;
else return dp[t][x][y] = 0;
}
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/913
参考资料:
https://leetcode.com/problems/cat-and-mouse/
[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)
[LeetCode] 913. Cat and Mouse 猫和老鼠的更多相关文章
- 【LeetCode】913. Cat and Mouse 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 参考资料 日期 题目地址:https://leetc ...
- [Swift]LeetCode913.猫与老鼠 | Cat and Mouse
A game on an undirected graph is played by two players, Mouse and Cat, who alternate turns. The grap ...
- 【LeetCode】代码模板,刷题必会
目录 二分查找 排序的写法 BFS的写法 DFS的写法 回溯法 树 递归 迭代 前序遍历 中序遍历 后序遍历 构建完全二叉树 并查集 前缀树 图遍历 Dijkstra算法 Floyd-Warshall ...
- 【LeetCode】576. Out of Boundary Paths 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 动态规划 状态搜索 记忆化搜索 相似题目 参考资料 ...
- leetcode hard
# Title Solution Acceptance Difficulty Frequency 4 Median of Two Sorted Arrays 27.2% Hard ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- 【LeetCode】一种博弈思路 minimax(共5题)
[292] Nim Game (2019年3月12日,E) 有一堆石头,游戏规则是每次可以从里面拿1-3颗石头,拿到最后的石头的人赢.你和你的对手都 optimal 的玩这个游戏,问先手(也就是你)能 ...
- 【17】有关python面向对象编程的提高【多继承、多态、类属性、动态添加与限制添加属性与方法、@property】
一.多继承 案例1:小孩继承自爸爸,妈妈.在程序入口模块再创建实例调用执行 #father模块 class Father(object): def __init__(self,money): self ...
- python实现类的多态
多态 关注公众号"轻松学编程"了解更多. 1.多态使用 一种事物的多种体现形式,举例:动物有很多种 注意: 继承是多态的前提 函数重写就是多态的体现形式 演示:重写Animal类 ...
随机推荐
- python免安装版(绿色版)制作
一.实验环境 1.Windows7x64_SP1 二.需求背景 个人编写了一个软件安装器,用于一键安装开发软件及工具,该工具基于python + pywinauto. 但问题来了,新电脑上未安装pyt ...
- 自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)
本文由作者FreddyChen原创分享,为了更好的体现文章价值,引用时有少许改动,感谢原作者. 1.写在前面 一直想写一篇关于im即时通讯分享的文章,无奈工作太忙,很难抽出时间.今天终于从公司离职了, ...
- 解决静态方法调用注入的service
在使用jpa的复杂查询时,声明了specification时声明为静态方法,导致注入的service无法使用,故想到俩种方式,一种手动注入,一种注解注入,此文使用的时注解注入: 解决静态方法调用注入的 ...
- Solr单机版的安装与使用
.使用Solr实现. 基于Solr实现站内搜索扩展性较好并且可以减少程序员的工作量,因为Solr提供了较为完备的搜索引擎解决方案,因此在门户.论坛等系统中常用此方案. .什么是Solr. Solr是A ...
- SpringBoot2版本Caused by: java.sql.SQLSyntaxErrorException: Table 'dinner.hibernate_sequenc
1.SpringBoot2版本Caused by: java.sql.SQLSyntaxErrorException: Table 'dinner.hibernate_sequenc报错. -java ...
- Windows Service 服务搭配FluentScheduler实现定时任务调度
Windows Service 服务 创建Windows Service 项目 创建一个Windows Service项目,并将项目名称改为 TaskWindowService 在解决方案资源管理器内 ...
- Lucene搜索/索引过程笔记
lucene索引文档过程: > 初始化IndexWriter > 构建Document > 调用IndexWriter.addDocument执行写入 > 初始化Documen ...
- 关于css中布局遇到的一些问题
现在本人初学网页布局经常遇到一些布局问题比如图片错位. 遇到的问题以及解决方案如下 行内元素有缝隙 块级元素没有缝隙 行内块元素中间会有小缝隙 常见的解决办法就是浮动
- MES助力日立电梯提升精细化管理水平
项目背景介绍 日立电梯在2008年到2012年期间分别在五地工厂(上海.广州.天津.成都.扶梯)上线了ERP系统,在后续的使用时间里,逐渐发现现有ERP系统对于生产现场管理,产品质量追溯,产能控制等方 ...
- iOS处理含中文的请求链接
NSString *urlStr = @""; // 将中文URL进行转码 urlStr = [urlStr stringByAddingPercentEscapesUsingEn ...