题目来源:https://leetcode.com/contest/weekly-contest-104/problems/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:
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
graph[1]
is non-empty.graph[2]
contains a non-zero element. ------------------------------------------------------------
题意
老鼠和猫在无向图上的博弈,无向图上编号为0的点表示老鼠洞。博弈规则为奇数turn老鼠走,偶数turn猫走,每个turn, 老鼠/猫都必须走向一个相邻节点。此外猫不能走到老鼠洞上。博弈结束规则有3条:
(1) 老鼠走到老鼠洞则老鼠胜利;
(2) 猫抓到老鼠(猫和老鼠在图的同一个节点)则猫胜利;
(3) 若出现重复的局势,则平局。
博弈开始前老鼠总是在节点1,猫总是在节点2.问给定无向图,老鼠/猫各自采取最优策略,求博弈结果(0表示平局,1表示老鼠胜利,2表示猫胜利)
------------------------------------------------------------
思路
这种图上的博弈论,不像经典的博弈论问题如Bash Game, Fibonacci Game, Wythoff Game, Nim Game有O(1)的解法。这类图上的博弈论需要用搜索,思路非常类似CCF 201803-4 棋局评估(博弈论),对于博弈双方,每步搜索都向着有利于自己的方向。为了加快速度,采用记忆化搜索,即用mat数组保存搜索结果。
值得注意的是记忆化数组维度是N×N×T,其中N是图的节点数T是博弈进行的最长轮数,而不能简单地用N×N,因为要考虑到之前是否经过某些节点,因此状态实际是当前博弈双方所在的节点和之前(T-1)轮双方经过的节点。其实应该对“之前经过的节点”进行状态压缩,比如用二进制表示每个节点是否被经过。这里用轮数t做状态压缩,这个地方笔者也没有考虑清楚,有时间再更。
博弈的最大轮数是2N, 因为老鼠最多经过N轮运动就能从图的任意节点走到节点0,如果博弈轮数超过2N(老鼠和猫各走N次),则老鼠一定走重复了。所以T的最大值是2N。
------------------------------------------------------------
代码
class Solution {
public:
vector> G;
int t = 0;
int n;
int mat[55][55][55]; // memory vector storing "dfs" result to speed up searching process
void init(vector> &graph)
{
G = graph;
n = G.size();
memset(mat, 0x3f, sizeof(mat));
}
int dfs(int x, int y, int t) // adversarial search, x: mouse position, y: cat position, t: turns
{
if (x == y)
{
return mat[x][y][t] = 2;
}
else if (x == 0)
{
return mat[x][y][t] = 1;
}
else if (t > 2 * n)
{
return 0;
}
else if (mat[x][y][t] != 0x3f3f3f3f)
{
return mat[x][y][t];
}
int i, len, v;
int cnt_lose, cnt_len;
vector edge;
if (t % 2 == 0) // mouse's turn
{
edge = G.at(x);
len = edge.size();
cnt_lose = 0;
for (i = 0; i < len; i++)
{
v = dfs(edge.at(i), y, t + 1);
if (v == 1)
{
return mat[x][y][t] = 1;
}
else if (v == 2)
{
cnt_lose++;
}
}
if (cnt_lose == len)
{
return mat[x][y][t] = 2;
}
else
{
return mat[x][y][t] = 0;
}
}
else // cat's turn
{
edge = G.at(y);
len = edge.size();
cnt_lose = cnt_len = 0;
for (i = 0; i < len; i++)
{
if (edge.at(i) != 0) // cat cannot go into hole
{
cnt_len++;
v = dfs(x, edge.at(i), t + 1);
if (v == 2)
{
return mat[x][y][t] = 2;
}
else if (v == 1)
{
cnt_lose++;
}
}
}
if (cnt_lose == cnt_len)
{
return mat[x][y][t] = 1;
}
else
{
return mat[x][y][t] = 0;
}
}
}
int catMouseGame(vector>& graph) {
init(graph);
return dfs(1, 2, 0);
}
};