913. Cat and Mouse (圖上博弈+ dp )
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
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;
}
}
};