LeetCode周赛#104 Q3 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表示猫胜利)

         

这道题感觉给的数据有问题,或者是题目表述有问题。例如无向图G:

      0

      |

4 – 1 – 3 – 2

对应的输入为:[[3], [4], [3], [0, 1, 2], [1]]

老鼠turn 1的最优策略是走到4(走到3的话turn 2就被猫抓到了),猫turn 2的最优策略是走到3(猫只能往3走,别无选择),老鼠turn 3的最优策略是走回1(老鼠也只有这个选择),平局,答案是0。但是LeetCode官方给出的答案是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做状态压缩,其实可能是一种错误的简化,不过鉴于题目数据有错,就这样吧不管他了。博弈的最大轮数是N, 因为老鼠最多经过N轮运动就能从图的任意节点走到节点0,如果博弈轮数超过N,则老鼠一定走重复了。

------------------------------------------------------------

代码

class Solution {
public:
	vector<vector<int>> G;
	int t = 0;
	int n;
	int mat[55][55][55];                        // memory vector storing "dfs" result to speed up searching process

	void init(vector<vector<int>> &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 > 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<int> 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<vector<int>>& graph) {
		init(graph);
		return dfs(1, 2, 0);
	}
};

猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/82949183
Q3
cat