【Leetcode 913】【Hard】Cat and Mouse 博弈论

小咪咪 2023-06-03 15:54 89阅读 0赞

描述

913. Cat and Mouse

Hard

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.

题解

本题是一个猫和老鼠的追逐博弈,题目的限制条件有:

1.老鼠先发,猫后走,轮流运动(而且必须运动,不能守株待兔)

2.老鼠初始在位置1,猫在位置2

3.猫和老鼠在同一位置,则猫胜;老鼠进洞则鼠胜

4.猫任何时候不能进洞

5.图是连通的

对本题的错误解法可能有:

1.从开始状态BFS模拟过程,直至有一方会输,然而一个状态可以有N条邻接的路可走,完全可以选一个不会输的路,所以这么解不行;比如对邻接图

0—2— 4— 5

  1. | |
  2. 3-- -----1

老鼠开始的模拟就会有一条输的路,但是它可以走另外一条路达成平局。

2.在1的基础上,考虑每次的所有选择,如果至少有一条成功,就不会输。这个解法也是错的,因为每一条路其实都不能提前确定最后的结果,即使当前选择了一条可能成功的路,也可能在后面失败,由于博弈的存在,当前节点(用m,c,turn表示)扩展到后面,其结果还要由另外一方来决定。这样,即使有成功的机会,也要往开始回溯,看是否能达到这样的状态。这样跟开始的顺推思路是矛盾的。

由于这种考虑,要用逆推法进行BFS回溯。从最后的结果来说,(m,c,turn)=(0,i,turn)的时候为mouse胜,(m,c,turn)=(i,i,turn)的时候为cat胜。

逆推的时候要注意博弈的思路,若当前状态下,A为胜,则上一步B不会走这条路,当然上一步B的选择自动减少1;若A为负,则上一步B必然会选择这条路。当上一步B的选择数为0,说明B必败。非平局的结果都被队列保存起来。

代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef struct State {
  4. int m, c, turn;
  5. State(int _m, int _c, int _turn):
  6. m(_m), c(_c), turn(_turn) {}
  7. } State;
  8. class Solution {
  9. public:
  10. enum winState {
  11. DRAW,
  12. WIN,
  13. LOST
  14. };
  15. enum turnState {
  16. MOUSE,
  17. CAT
  18. };
  19. int catMouseGame(vector<vector<int> >& graph) {
  20. int n = graph.size();
  21. vector<vector<vector<int> > > res(n,
  22. vector<vector<int> >(n, vector<int>(2, 0)));
  23. vector<vector<vector<int> > > child(n,
  24. vector<vector<int> >(n, vector<int>(2, 0)));
  25. int m, c;
  26. for (int i = 0; i < n; i++) {
  27. // if mouse is in hole, for mouse it wins
  28. res[0][i][MOUSE] = WIN;
  29. res[0][i][CAT] = LOST;
  30. if (i) {
  31. res[i][i][MOUSE] = LOST;
  32. res[i][i][CAT] = WIN;
  33. }
  34. for (int j = 0; j < n; j++) {
  35. // number of next possible positions from current state
  36. child[i][j][MOUSE] = graph[i].size();
  37. child[i][j][CAT] = graph[j].size();
  38. for (auto& k: graph[j]) {
  39. if (k == 0) {
  40. child[i][j][CAT]--;
  41. break;
  42. }
  43. }
  44. }
  45. }
  46. queue<State> q;
  47. for (m = 0; m < n; m++) {
  48. for (c = 0; c < n; c++) {
  49. for (int turn = 0; turn <= 1; turn++) {
  50. if (res[m][c][turn] != DRAW) {
  51. // add states that will lead to result state
  52. q.push({m, c, turn});
  53. }
  54. }
  55. }
  56. }
  57. while (!q.empty()) {
  58. State f = q.front();
  59. q.pop();
  60. int prev_turn = 1 - f.turn;
  61. int curState = res[f.m][f.c][f.turn];
  62. int prev_m, prev_c;
  63. int adj = prev_turn == CAT ? f.c : f.m;
  64. // visit adj positions that are not yet expanded
  65. for (auto& v: graph[adj]) {
  66. prev_m = prev_turn == MOUSE ? v : f.m;
  67. prev_c = prev_turn == CAT ? v : f.c;
  68. if (!prev_c) continue;
  69. if (res[prev_m][prev_c][prev_turn] != DRAW) continue;
  70. if (curState == LOST) {
  71. res[prev_m][prev_c][prev_turn] = WIN;
  72. q.push({prev_m, prev_c, prev_turn});
  73. } else {
  74. child[prev_m][prev_c][prev_turn]--;
  75. if (!child[prev_m][prev_c][prev_turn])
  76. {
  77. res[prev_m][prev_c][prev_turn] = LOST;
  78. q.push({prev_m, prev_c, prev_turn});
  79. }
  80. }
  81. }
  82. }
  83. return res[1][2][MOUSE];
  84. }
  85. };

测试用例

  1. int main() {
  2. Solution sol;
  3. int n, m;
  4. while (cin >> n) {
  5. if (n < 3) {
  6. cout << "error input\n";
  7. continue;
  8. }
  9. vector<vector<int> > graph(n);
  10. int u, v;
  11. int edge;
  12. cin >> edge;
  13. for (int i = 0; i < edge; i++) {
  14. cin >> u >> v;
  15. graph[u].push_back(v);
  16. graph[v].push_back(u);
  17. }
  18. cout << sol.catMouseGame(graph) << endl;
  19. }
  20. return 0;
  21. }
  22. In:
  23. 3
  24. 2
  25. 0 1
  26. 1 2
  27. Out:
  28. 1
  29. In:
  30. 6
  31. 7
  32. 0 2
  33. 0 5
  34. 2 5
  35. 4 3
  36. 2 4
  37. 3 5
  38. 1 3
  39. Out:
  40. 0
  41. In:
  42. 5
  43. 5
  44. 0 3
  45. 1 3
  46. 2 3
  47. 1 4
  48. 2 4
  49. Out:
  50. 2

References:

https://leetcode.com/problems/cat-and-mouse/

转载于:https://www.cnblogs.com/wangzming/p/11579770.html

发表评论

表情:
评论列表 (有 0 条评论,89人围观)

还没有评论,来说两句吧...

相关阅读

    相关 博弈论

    博弈论 看了两天博弈,做了一点题,写一写,把自己学会的东西记录下来。 巴什博奕(Bash Game) 只有一堆n个物品,两个人轮流从这

    相关 博弈论模板

    一。巴什博弈 只是最简单的博弈了,只简单说一下满足条件,一堆总数为n个,每次可以取1-m个石头。 核心是n=(m+1)\r+s;也就是说用n%(m+1) 判断是否等于0即可。

    相关 博弈论

    博弈论 巴什博弈 尼姆博弈 威佐夫博弈 巴什博弈 问题类型: 只有一堆n个物品,两个人从轮流中取出(1~m)个,最后取光者得胜; bo

    相关 博弈论问题

    \\ 博弈论问题——双人取棋子 \\ 1.问题描述 一共有19枚棋子,两人轮流取,每人每次可以取1枚或2枚或3枚,己方先取,拿到最后一枚棋子算输,问何种取法可以