CC

自然万物都趋向从有序变得无序

0%

leetcode-913 猫和老鼠

913. 猫和老鼠 - 力扣(LeetCode) (leetcode-cn.com)

题目

两位玩家分别扮演猫和老鼠,在一张 无向 图上进行游戏,两人轮流行动。

图的形式是:graph[a] 是一个列表,由满足 ab 是图中的一条边的所有节点 b 组成。

老鼠从节点 1 开始,第一个出发;猫从节点 2 开始,第二个出发。在节点 0 处有一个洞。

在每个玩家的行动中,他们 必须 沿着图中与所在当前位置连通的一条边移动。例如,如果老鼠在节点 1 ,那么它必须移动到 graph[1] 中的任一节点。

此外,猫无法移动到洞中(节点 0)。

然后,游戏在出现以下三种情形之一时结束:

如果猫和老鼠出现在同一个节点,猫获胜。
如果老鼠到达洞中,老鼠获胜。
如果某一位置重复出现(即,玩家的位置和移动顺序都与上一次行动相同),游戏平局。
给你一张图 graph ,并假设两位玩家都都以最佳状态参与游戏:

如果老鼠获胜,则返回 1;
如果猫获胜,则返回 2;
如果平局,则返回 0 。

题意

在一个无向图中,进猫捉老鼠的游戏。

如果猫和老鼠位于同一位置,则猫赢。

如果老鼠走到节点0,则老鼠赢。

如果某一位置重复出现,则平局。此时应该是猫和老鼠都出现在了重复的位置,才是平局,否则只是单纯的一方出现在重复的位置,那么实则另一方还是有可能会获胜,因为他还有没有走完的位置,还有可能性。

思路

记忆化搜索或者说动态规划

博弈问题,猫和老鼠都足够聪明,那么每一轮,只要当前轮的玩家(猫或者老鼠)在走的时候存在着一种可能性使它获胜,那么此轮玩家一定会走向让自己获胜的那个节点,否则会走向平局的节点,如果没有能平局的点,最后则会走向让自己输的节点。

因此平局的可能性可以表示为,当轮数i大于2*n(n表示总共节点数),可以理解为此时猫和老鼠都走过了n个节点,那么下一轮的节点必定都是重复的。

那么其实就可以用搜索达到上面的过程,对于每一轮,可以使用搜索穷尽子问题的所有状态达到上述的结果。

但是单纯的搜索会超时,因此需要记忆化

令dp[i][j][k]表示第i轮,老鼠在编号为j的节点,猫在编号为k的节点,表示此轮已经得到的是猫赢或者老鼠赢,或者平局。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
* @File Name :leetcode-913.cpp
* @Author :cc
* @Version :1.0.0
* @Date :2022/1/4 9:13
* @Description :
* @Function List :
* @History :
*/

#include "algorithm"
#include "vector"
#include "string"

using namespace std;

class Solution {
public:
int dp[100][100][100];

int catMouseGame(vector<vector<int>> &graph) {
for (int i = 0; i < 100; i++)
for(int j = 0; j < 100; j++)
for(int k = 0; k < 100; k++)
dp[k][i][j] = -1;
return dfs(1, 2, graph, 0);
}

//st=0表示mouse该移动
int dfs(int curMouse, int curCat, vector<vector<int>> &graph, int st) {
if (dp[st][curCat][curMouse] != -1) return dp[st][curCat][curMouse];
if (st > 2 * graph.size()) return 0;
if (curMouse == 0) return 1;
if (curMouse == curCat) return 2;
if (st % 2 == 0) {
int k = 2;
for (auto &x: graph[curMouse]) {
int t = dfs(x, curCat, graph, st + 1);
if (t == 1) {
dp[st][curCat][curMouse] = 1;
return 1;
}
else if (t == 0) k = 0;
}dp[st][curCat][curMouse] = k;
return k;
} else {
int k = 1;
for (auto &x: graph[curCat])
if (x) {
int t = dfs(curMouse, x, graph, st + 1);
if (t == 2) {
dp[st][curMouse][curCat] = 2;
return 2;
}
else if (t == 0) k = 0;
}dp[st][curCat][curMouse] = k;
return k;
}
}
};