当前位置:  首页>> 技术小册>> 数据结构与算法(中)

难度:
Hard

题意:

  1. 给定一张图,猫和鼠轮流走动,每一次可以走到当前点的下一个节点
  2. 猫胜利的条件是猫和老鼠在同一个位置
  3. 老鼠胜利的条件是到达0号节点
  4. 如果猫和老鼠所到达的状态是先前他们走过的状态,则平局
  5. 猫和鼠都是选择对它们最优的策略走

思路:

  • 零和博弈
  • 轮到猫走的时候,猫会选择一个状态,使得这个状态下猫必胜利
  • 如果找不到一个子状态必胜,那么猫会找一个平局的状态进行游戏
  • 如果找不到一个必胜和一个平局的状态,那么这个状态下只能鼠胜出
  • 轮到鼠走时也是如此
  • 令状态表达式是f[first][cat][mouse]表示猫或者鼠先走时,猫在cat的位置,鼠在mouse的位置的状态,状态值是猫(2)或鼠(1)胜利,或者平局(0)
  • 根据博弈的条件,可以得出状态转移公式和初始状态
  • 这个题最难的地方不在公式,而是无子问题。无法用递推或者递归的方式解决问题。借助一下最短路松弛算法,我们可以从初始状态出发,然后影响周边状态,假设某个状态值改变了,需要对这个状态的周边状态进行重新计算,直到收敛

代码:

  1. class Solution {
  2. private class Node {
  3. int first;
  4. int mouse;
  5. int cat;
  6. public Node(int first, int cat, int mouse) {
  7. this.first = first;
  8. this.mouse = mouse;
  9. this.cat = cat;
  10. }
  11. public int getFirst() {
  12. return first;
  13. }
  14. public void setFirst(int first) {
  15. this.first = first;
  16. }
  17. public int getMouse() {
  18. return mouse;
  19. }
  20. public void setMouse(int mouse) {
  21. this.mouse = mouse;
  22. }
  23. public int getCat() {
  24. return cat;
  25. }
  26. public void setCat(int cat) {
  27. this.cat = cat;
  28. }
  29. }
  30. private int solve(int[][] graph) {
  31. int[][][] cache = new int[2][graph.length][graph.length];
  32. for (int first = 0;first < 2;first++) {
  33. for (int cat = 0;cat < graph.length;cat++) {
  34. for (int mouse = 0;mouse < graph.length;mouse++) {
  35. cache[first][cat][mouse] = 0;
  36. }
  37. }
  38. }
  39. Queue<Node> nodes = new LinkedList<>();
  40. for (int first = 0;first < 2;first++) {
  41. for (int cat = 1; cat < graph.length; cat++) {
  42. for (int mouse = 0; mouse < graph.length; mouse++) {
  43. if (mouse == 0) {
  44. cache[first][cat][mouse] = 1;
  45. nodes.add(new Node(first, cat, mouse));
  46. }
  47. if (cat == mouse) {
  48. cache[first][cat][mouse] = 2;
  49. nodes.add(new Node(first, cat, mouse));
  50. }
  51. }
  52. }
  53. }
  54. while (!nodes.isEmpty()) {
  55. Node node = nodes.poll();
  56. if (node.first == 0) {
  57. for (int i = 0;i < graph[node.mouse].length;i++) {
  58. int x = graph[node.mouse][i];
  59. int pre = cache[1][node.cat][x];
  60. if (x == 0 || node.cat == x) {
  61. continue;
  62. }
  63. boolean findWin = false;
  64. boolean findDraw = false;
  65. for (int j = 0;j < graph[x].length;j++) {
  66. int y = graph[x][j];
  67. if (cache[0][node.cat][y] == 1) {
  68. findWin = true;
  69. } else if (cache[0][node.cat][y] == 0) {
  70. findDraw = true;
  71. }
  72. }
  73. if (findWin) {
  74. cache[1][node.cat][x] = 1;
  75. } else if (!findDraw) {
  76. cache[1][node.cat][x] = 2;
  77. } else {
  78. cache[1][node.cat][x] = 0;
  79. }
  80. if (cache[1][node.cat][x] != pre) {
  81. nodes.add(new Node(1, node.cat, x));
  82. }
  83. }
  84. } else {
  85. for (int i = 0;i < graph[node.cat].length;i++) {
  86. int x = graph[node.cat][i];
  87. int pre = cache[0][x][node.mouse];
  88. if (x == 0 || node.mouse == x) {
  89. continue;
  90. }
  91. boolean findWin = false;
  92. boolean findDraw = false;
  93. for (int j = 0;j < graph[x].length;j++) {
  94. int y = graph[x][j];
  95. if (y == 0) {
  96. continue;
  97. }
  98. if (cache[1][y][node.mouse] == 2) {
  99. findWin = true;
  100. } else if (cache[1][y][node.mouse] == 0) {
  101. findDraw = true;
  102. }
  103. }
  104. if (findWin) {
  105. cache[0][x][node.mouse] = 2;
  106. } else if (!findDraw) {
  107. cache[0][x][node.mouse] = 1;
  108. } else {
  109. cache[0][x][node.mouse] = 0;
  110. }
  111. if (pre != cache[0][x][node.mouse]) {
  112. nodes.add(new Node(0, x, node.mouse));
  113. }
  114. }
  115. }
  116. }
  117. return cache[1][2][1];
  118. }
  119. public int catMouseGame(int[][] graph) {
  120. int ret = solve(graph);
  121. return ret;
  122. }
  123. }

该分类下的相关小册推荐: