LeetCode周赛#104 Q4 Cat and Mouse (图论+博弈论,记忆化搜索)

题目来源:https://leetcode.com/contest/weekly-contest-104/problems/cat-and-mouse/

问题描述

913. 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:

  • 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:

  1. 3 <= graph.length <= 50
  2. It is guaranteed that graph[1] is non-empty.
  3. It is guaranteed that 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);
	}
};

 

你可能感兴趣的:(基础算法,LeetCode)