<p>A game on an <strong>undirected</strong> graph is played by two players, Mouse and Cat, who alternate turns.</p>

<p>The graph is given as follows: <code>graph[a]</code> is a list of all nodes <code>b</code> such that <code>ab</code> is an edge of the graph.</p>

<p>The mouse starts at node <code>1</code> and goes first, the cat starts at node <code>2</code> and goes second, and there is a hole at node <code>0</code>.</p>

<p>During each player&#39;s turn, they <strong>must</strong> travel along one&nbsp;edge of the graph that meets where they are.&nbsp; For example, if the Mouse is at node 1, it <strong>must</strong> travel to any node in <code>graph[1]</code>.</p>

<p>Additionally, it is not allowed for the Cat to travel to the Hole (node <code>0</code>).</p>

<p>Then, the game can end in three&nbsp;ways:</p>

<ul>
	<li>If ever the Cat occupies the same node as the Mouse, the Cat wins.</li>
	<li>If ever the Mouse reaches the Hole, the Mouse wins.</li>
	<li>If ever a position is repeated (i.e., the players are in the same position as a previous turn, and&nbsp;it is the same player&#39;s turn to move), the game is a draw.</li>
</ul>

<p>Given a <code>graph</code>, and assuming both players play optimally, return</p>

<ul>
	<li><code>1</code>&nbsp;if the mouse wins the game,</li>
	<li><code>2</code>&nbsp;if the cat wins the game, or</li>
	<li><code>0</code>&nbsp;if the game is a draw.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/11/17/cat1.jpg" style="width: 300px; height: 300px;" />
<pre>
<strong>Input:</strong> graph = [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
<strong>Output:</strong> 0
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/11/17/cat2.jpg" style="width: 200px; height: 200px;" />
<pre>
<strong>Input:</strong> graph = [[1,3],[0],[3],[0,2]]
<strong>Output:</strong> 1
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>3 &lt;= graph.length &lt;= 50</code></li>
	<li><code>1&nbsp;&lt;= graph[i].length &lt; graph.length</code></li>
	<li><code>0 &lt;= graph[i][j] &lt; graph.length</code></li>
	<li><code>graph[i][j] != i</code></li>
	<li><code>graph[i]</code> is unique.</li>
	<li>The mouse and the cat can always move.&nbsp;</li>
</ul>

#include <vector>
#include <queue>
#include <iostream>

using namespace std;

class Solution {
public:
    int catMouseGame(vector<vector<int>>& graph) {
        int n = graph.size();
        
        // 3D DP table: dp[mouse][cat][turn]
        // 0: Draw, 1: Mouse wins, 2: Cat wins
        vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(3, 0)));
        // Degree table for each state
        vector<vector<vector<int>>> degree(n, vector<vector<int>>(n, vector<int>(3, 0)));
        
        // Initialize degree for each state
        for (int m = 0; m < n; ++m) {
            for (int c = 0; c < n; ++c) {
                // Mouse's turn
                degree[m][c][1] = graph[m].size();
                // Cat's turn, excluding moves to hole (node 0)
                degree[m][c][2] = graph[c].size() - (find(graph[c].begin(), graph[c].end(), 0) != graph[c].end() ? 1 : 0);
            }
        }
        
        // Queue for BFS: (mouse, cat, turn, result)
        queue<tuple<int, int, int, int>> q;
        
        // Initialize base cases
        for (int i = 0; i < n; ++i) {
            for (int turn = 1; turn <= 2; ++turn) {
                // Mouse at hole, mouse wins
                dp[0][i][turn] = 1;
                q.emplace(0, i, turn, 1);
                // Cat catches mouse, cat wins
                if (i > 0) {
                    dp[i][i][turn] = 2;
                    q.emplace(i, i, turn, 2);
                }
            }
        }
        
        // Perform reverse BFS
        while (!q.empty()) {
            auto [mouse, cat, turn, result] = q.front();
            q.pop();
            int prev_turn = (turn == 1) ? 2 : 1;
            for (auto [prev_mouse, prev_cat] : getPrevStates(graph, mouse, cat, turn)) {
                if (dp[prev_mouse][prev_cat][prev_turn] == 0) {
                    if (result == 3 - turn) {
                        dp[prev_mouse][prev_cat][prev_turn] = result;
                        q.emplace(prev_mouse, prev_cat, prev_turn, result);
                    } else {
                        degree[prev_mouse][prev_cat][prev_turn]--;
                        if (degree[prev_mouse][prev_cat][prev_turn] == 0) {
                            dp[prev_mouse][prev_cat][prev_turn] = turn;
                            q.emplace(prev_mouse, prev_cat, prev_turn, turn);
                        }
                    }
                }
            }
        }
        
        return dp[1][2][1];
    }
    
private:
    vector<pair<int, int>> getPrevStates(const vector<vector<int>>& graph, int mouse, int cat, int turn) {
        vector<pair<int, int>> prevStates;
        int prev_turn = (turn == 1) ? 2 : 1;
        if (prev_turn == 1) {  // Mouse's turn
            for (int prev_mouse : graph[mouse]) {
                prevStates.emplace_back(prev_mouse, cat);
            }
        } else {  // Cat's turn
            for (int prev_cat : graph[cat]) {
                if (prev_cat != 0) {
                    prevStates.emplace_back(mouse, prev_cat);
                }
            }
        }
        return prevStates;
    }
};

68425