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.
设状态 f(t,x,y)f(t,x,y) 表示 tt 时刻,老鼠位于 xx 且猫位于 yy 时的结果(0,1 或 2)。
如果当前为老鼠行动,那么他可以走到 f(t+1,i,y),i∈graph[x]f(t+1,i,y),i∈graph[x],如果他走到的这些点结果都是 2,则老鼠必输无疑;若其中有一个是 1,则老鼠必获胜;否则结果就是平局。
对于猫来说,以上分析相反。
我们已经知道的状态有,f(t,0,y)=1f(t,0,y)=1,f(t,x,x)=2f(t,x,x)=2,分别代表老鼠获胜和猫获胜。
若游戏进行了 2n2n 个单位时间还没有结束,则可以宣布平局(待证明,以下为直觉想法)。因为每一次移动老鼠都有可能到达一个新的位置,所以它最多只需要 2n2n 步就可能找到出口(因为猫对应也走了 nn 步)。若超过了 2n2n 步,则老鼠必定走了回头路,此时不管猫在哪,走回头路都是向猫 “妥协” 的选择;同理对猫来说,走回头路也是向老鼠 “妥协” 的结果;故最大的 tt 只需要 2n2n 即可。
我们从 solve(0,1,2)solve(0,1,2) 开始记忆化搜索即可。
思路:设定当前为第k步,老鼠在x点,猫在y点,那么若老鼠win则计为1,猫win则计为2,平局计为0
根据博弈性质,若后面全为必败态,那么当前是必败的,如后面有必胜态,则当前是必胜的。
因此,可以根据这个性质去深度优先遍历决定当前状态是必胜还是必败。
代码:
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int dp[200][100][100];
int catMouseGame(vector<vector<int>>& graph) {
int n = graph.size();
memset(dp,-1,sizeof(dp));
return solve(graph,0,1,2);
}
int solve(vector<vector<int>>& graph,int t,int x,int y)
{
if(t>=2*graph.size())
{
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];
}
int who = t%2;
if(who==0)
{
bool f= 1;
for(int i=0;i<graph[x].size();i++)
{
int nxt = solve(graph,t+1,graph[x][i],y);
if(nxt==1)
{
return dp[t][x][y]=1;
}
else if(nxt!=2)
{
f=0;
}
}
if(f)
{
return dp[t][x][y]=2;
}
else
{
return dp[t][x][y]=0;
}
}
else
{
bool f=1;
for(int i=0;i<graph[y].size();i++)
{
if(graph[y][i]==0) continue;
int nxt = solve(graph,t+1,x,graph[y][i]);
if(nxt==2)
{
return dp[t][x][y]=2;
}
else if(nxt!=1)
{
f=0;
}
}
if(f)
{
return dp[t][x][y]=1;
}
else return dp[t][x][y]=0;
}
}
};