Welcome to Subscribe On Youtube
1728. Cat and Mouse II
Description
A game is played by a cat and a mouse named Cat and Mouse.
The environment is represented by a grid
of size rows x cols
, where each element is a wall, floor, player (Cat, Mouse), or food.
- Players are represented by the characters
'C'
(Cat),'M'
(Mouse). - Floors are represented by the character
'.'
and can be walked on. - Walls are represented by the character
'#'
and cannot be walked on. - Food is represented by the character
'F'
and can be walked on. - There is only one of each character
'C'
,'M'
, and'F'
ingrid
.
Mouse and Cat play according to the following rules:
- Mouse moves first, then they take turns to move.
- During each turn, Cat and Mouse can jump in one of the four directions (left, right, up, down). They cannot jump over the wall nor outside of the
grid
. catJump, mouseJump
are the maximum lengths Cat and Mouse can jump at a time, respectively. Cat and Mouse can jump less than the maximum length.- Staying in the same position is allowed.
- Mouse can jump over Cat.
The game can end in 4 ways:
- If Cat occupies the same position as Mouse, Cat wins.
- If Cat reaches the food first, Cat wins.
- If Mouse reaches the food first, Mouse wins.
- If Mouse cannot get to the food within 1000 turns, Cat wins.
Given a rows x cols
matrix grid
and two integers catJump
and mouseJump
, return true
if Mouse can win the game if both Cat and Mouse play optimally, otherwise return false
.
Example 1:
Input: grid = ["####F","#C...","M...."], catJump = 1, mouseJump = 2 Output: true Explanation: Cat cannot catch Mouse on its turn nor can it get the food before Mouse.
Example 2:
Input: grid = ["M.C...F"], catJump = 1, mouseJump = 4 Output: true
Example 3:
Input: grid = ["M.C...F"], catJump = 1, mouseJump = 3 Output: false
Constraints:
rows == grid.length
cols = grid[i].length
1 <= rows, cols <= 8
grid[i][j]
consist only of characters'C'
,'M'
,'F'
,'.'
, and'#'
.- There is only one of each character
'C'
,'M'
, and'F'
ingrid
. 1 <= catJump, mouseJump <= 8
Solutions
-
class Solution: def canMouseWin(self, grid: List[str], catJump: int, mouseJump: int) -> bool: dirs = [0, 1, 0, -1, 0] m = len(grid) n = len(grid[0]) nFloors = 0 cat = 0 # cat's position mouse = 0 # mouse's position def hash(i: int, j: int) -> int: return i * n + j for i in range(m): for j in range(n): if grid[i][j] != "#": nFloors += 1 if grid[i][j] == "C": cat = hash(i, j) elif grid[i][j] == "M": mouse = hash(i, j) # dp(i, j, k) := True if mouse can win w// # Cat on (i // 8, i % 8), mouse on (j // 8, j % 8), and turns = k @functools.lru_cache(None) def dp(cat: int, mouse: int, turn: int) -> bool: # We already search whole touchable grid if turn == nFloors * 2: return False if turn % 2 == 0: # mouse's turn i = mouse // n j = mouse % n for k in range(4): for jump in range(mouseJump + 1): x = i + dirs[k] * jump y = j + dirs[k + 1] * jump if x < 0 or x == m or y < 0 or y == n: break if grid[x][y] == "#": break if grid[x][y] == "F": # Mouse eats the food, so mouse win return True if dp(cat, hash(x, y), turn + 1): return True # Mouse can't win, so mouse lose return False else: # cat's turn i = cat // n j = cat % n for k in range(4): for jump in range(catJump + 1): x = i + dirs[k] * jump y = j + dirs[k + 1] * jump if x < 0 or x == m or y < 0 or y == n: break if grid[x][y] == "#": break if grid[x][y] == "F": # Cat eats the food, so mouse lose return False nextCat = hash(x, y) if nextCat == mouse: # Cat catches mouse, so mouse lose return False if not dp(nextCat, mouse, turn + 1): return False # Cat can't win, so mouse win return True return dp(cat, mouse, 0)
-
class Solution { private final int[] dirs = {-1, 0, 1, 0, -1}; public boolean canMouseWin(String[] grid, int catJump, int mouseJump) { int m = grid.length; int n = grid[0].length(); int catStart = 0, mouseStart = 0, food = 0; List<Integer>[] gMouse = new List[m * n]; List<Integer>[] gCat = new List[m * n]; Arrays.setAll(gMouse, i -> new ArrayList<>()); Arrays.setAll(gCat, i -> new ArrayList<>()); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { char c = grid[i].charAt(j); if (c == '#') { continue; } int v = i * n + j; if (c == 'C') { catStart = v; } else if (c == 'M') { mouseStart = v; } else if (c == 'F') { food = v; } for (int d = 0; d < 4; ++d) { for (int k = 0; k <= mouseJump; k++) { int x = i + k * dirs[d]; int y = j + k * dirs[d + 1]; if (x < 0 || x >= m || y < 0 || y >= n || grid[x].charAt(y) == '#') { break; } gMouse[v].add(x * n + y); } for (int k = 0; k <= catJump; k++) { int x = i + k * dirs[d]; int y = j + k * dirs[d + 1]; if (x < 0 || x >= m || y < 0 || y >= n || grid[x].charAt(y) == '#') { break; } gCat[v].add(x * n + y); } } } } return calc(gMouse, gCat, mouseStart, catStart, food) == 1; } private int calc( List<Integer>[] gMouse, List<Integer>[] gCat, int mouseStart, int catStart, int hole) { int n = gMouse.length; int[][][] degree = new int[n][n][2]; int[][][] ans = new int[n][n][2]; Deque<int[]> q = new ArrayDeque<>(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { degree[i][j][0] = gMouse[i].size(); degree[i][j][1] = gCat[j].size(); } } for (int i = 0; i < n; i++) { ans[hole][i][1] = 1; ans[i][hole][0] = 2; ans[i][i][1] = 2; ans[i][i][0] = 2; q.offer(new int[] {hole, i, 1}); q.offer(new int[] {i, hole, 0}); q.offer(new int[] {i, i, 0}); q.offer(new int[] {i, i, 1}); } while (!q.isEmpty()) { int[] state = q.poll(); int m = state[0], c = state[1], t = state[2]; int result = ans[m][c][t]; for (int[] prevState : getPrevStates(gMouse, gCat, state, ans)) { int pm = prevState[0], pc = prevState[1], pt = prevState[2]; if (pt == result - 1) { ans[pm][pc][pt] = result; q.offer(prevState); } else { degree[pm][pc][pt]--; if (degree[pm][pc][pt] == 0) { ans[pm][pc][pt] = result; q.offer(prevState); } } } } return ans[mouseStart][catStart][0]; } private List<int[]> getPrevStates( List<Integer>[] gMouse, List<Integer>[] gCat, int[] state, int[][][] ans) { int m = state[0], c = state[1], t = state[2]; int pt = t ^ 1; List<int[]> pre = new ArrayList<>(); if (pt == 1) { for (int pc : gCat[c]) { if (ans[m][pc][1] == 0) { pre.add(new int[] {m, pc, pt}); } } } else { for (int pm : gMouse[m]) { if (ans[pm][c][0] == 0) { pre.add(new int[] {pm, c, 0}); } } } return pre; } }
-
class Solution { private: const int dirs[5] = {-1, 0, 1, 0, -1}; int calc(vector<vector<int>>& gMouse, vector<vector<int>>& gCat, int mouseStart, int catStart, int hole) { int n = gMouse.size(); vector<vector<vector<int>>> degree(n, vector<vector<int>>(n, vector<int>(2))); vector<vector<vector<int>>> ans(n, vector<vector<int>>(n, vector<int>(2))); queue<tuple<int, int, int>> q; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { degree[i][j][0] = gMouse[i].size(); degree[i][j][1] = gCat[j].size(); } } for (int i = 0; i < n; i++) { ans[hole][i][1] = 1; ans[i][hole][0] = 2; ans[i][i][1] = 2; ans[i][i][0] = 2; q.push(make_tuple(hole, i, 1)); q.push(make_tuple(i, hole, 0)); q.push(make_tuple(i, i, 0)); q.push(make_tuple(i, i, 1)); } while (!q.empty()) { auto state = q.front(); q.pop(); int m = get<0>(state), c = get<1>(state), t = get<2>(state); int result = ans[m][c][t]; for (auto& prevState : getPrevStates(gMouse, gCat, state, ans)) { int pm = get<0>(prevState), pc = get<1>(prevState), pt = get<2>(prevState); if (pt == result - 1) { ans[pm][pc][pt] = result; q.push(prevState); } else { degree[pm][pc][pt]--; if (degree[pm][pc][pt] == 0) { ans[pm][pc][pt] = result; q.push(prevState); } } } } return ans[mouseStart][catStart][0]; } vector<tuple<int, int, int>> getPrevStates(vector<vector<int>>& gMouse, vector<vector<int>>& gCat, tuple<int, int, int>& state, vector<vector<vector<int>>>& ans) { int m = get<0>(state), c = get<1>(state), t = get<2>(state); int pt = t ^ 1; vector<tuple<int, int, int>> pre; if (pt == 1) { for (int pc : gCat[c]) { if (ans[m][pc][1] == 0) { pre.push_back(make_tuple(m, pc, pt)); } } } else { for (int pm : gMouse[m]) { if (ans[pm][c][0] == 0) { pre.push_back(make_tuple(pm, c, 0)); } } } return pre; } public: bool canMouseWin(vector<string>& grid, int catJump, int mouseJump) { int m = grid.size(); int n = grid[0].length(); int catStart = 0, mouseStart = 0, food = 0; vector<vector<int>> gMouse(m * n); vector<vector<int>> gCat(m * n); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { char c = grid[i][j]; if (c == '#') { continue; } int v = i * n + j; if (c == 'C') { catStart = v; } else if (c == 'M') { mouseStart = v; } else if (c == 'F') { food = v; } for (int d = 0; d < 4; ++d) { for (int k = 0; k <= mouseJump; k++) { int x = i + k * dirs[d]; int y = j + k * dirs[d + 1]; if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == '#') { break; } gMouse[v].push_back(x * n + y); } for (int k = 0; k <= catJump; k++) { int x = i + k * dirs[d]; int y = j + k * dirs[d + 1]; if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == '#') { break; } gCat[v].push_back(x * n + y); } } } } return calc(gMouse, gCat, mouseStart, catStart, food) == 1; } };
-
func canMouseWin(grid []string, catJump int, mouseJump int) bool { m, n := len(grid), len(grid[0]) catStart, mouseStart, food := 0, 0, 0 dirs := []int{-1, 0, 1, 0, -1} gMouse := make([][]int, m*n) gCat := make([][]int, m*n) for i := 0; i < m; i++ { for j := 0; j < n; j++ { c := grid[i][j] if c == '#' { continue } v := i*n + j if c == 'C' { catStart = v } else if c == 'M' { mouseStart = v } else if c == 'F' { food = v } for d := 0; d < 4; d++ { a, b := dirs[d], dirs[d+1] for k := 0; k <= mouseJump; k++ { x, y := i+k*a, j+k*b if !(0 <= x && x < m && 0 <= y && y < n && grid[x][y] != '#') { break } gMouse[v] = append(gMouse[v], x*n+y) } for k := 0; k <= catJump; k++ { x, y := i+k*a, j+k*b if !(0 <= x && x < m && 0 <= y && y < n && grid[x][y] != '#') { break } gCat[v] = append(gCat[v], x*n+y) } } } } return calc(gMouse, gCat, mouseStart, catStart, food) == 1 } func calc(gMouse, gCat [][]int, mouseStart, catStart, hole int) int { n := len(gMouse) degree := make([][][]int, n) ans := make([][][]int, n) for i := 0; i < n; i++ { degree[i] = make([][]int, n) ans[i] = make([][]int, n) for j := 0; j < n; j++ { degree[i][j] = make([]int, 2) ans[i][j] = make([]int, 2) degree[i][j][0] = len(gMouse[i]) degree[i][j][1] = len(gCat[j]) } } q := list.New() for i := 0; i < n; i++ { ans[hole][i][1] = 1 ans[i][hole][0] = 2 ans[i][i][1] = 2 ans[i][i][0] = 2 q.PushBack([]int{hole, i, 1}) q.PushBack([]int{i, hole, 0}) q.PushBack([]int{i, i, 0}) q.PushBack([]int{i, i, 1}) } for q.Len() > 0 { front := q.Front() q.Remove(front) state := front.Value.([]int) m, c, t := state[0], state[1], state[2] currentAns := ans[m][c][t] for _, prevState := range getPrevStates(gMouse, gCat, m, c, t, ans) { pm, pc, pt := prevState[0], prevState[1], prevState[2] if pt == currentAns-1 { ans[pm][pc][pt] = currentAns q.PushBack([]int{pm, pc, pt}) } else { degree[pm][pc][pt]-- if degree[pm][pc][pt] == 0 { ans[pm][pc][pt] = currentAns q.PushBack([]int{pm, pc, pt}) } } } } return ans[mouseStart][catStart][0] } func getPrevStates(gMouse, gCat [][]int, m, c, t int, ans [][][]int) [][]int { pt := t ^ 1 pre := [][]int{} if pt == 1 { for _, pc := range gCat[c] { if ans[m][pc][1] == 0 { pre = append(pre, []int{m, pc, pt}) } } } else { for _, pm := range gMouse[m] { if ans[pm][c][0] == 0 { pre = append(pre, []int{pm, c, pt}) } } } return pre }