1728. 猫和老鼠 II 记忆化搜索 暴力
题目大意:
中文题目就自己看吧,但是要注意一下这个题目的数据范围:
- (rows == grid.length)
- (cols = grid[i].length)
- (1 <= rows, cols <= 8)
- (grid[i][j]) 只包含字符 ('C') ,('M') ,('F') ,('.') 和 ('#') 。
- (grid) 中只包含一个 $'C' (,)'M'$ 和 $'F' $。
- (1 <= catJump, mouseJump <= 8)
题解:
这种带有博弈性质的题目,如果范围小可以直接暴力搜索,然后可以加一点优化就是记忆化搜索。
定义(dp[x1][y1][x2][y2][step][now]) 表示当前老鼠在位置 ((x1,y1)) ,猫在位置 ((x2,y2)) ,已经走了 (step) 步了,当前的先手是 老鼠now = 0,猫 now = 1。
对于先手来说只要子状态有一个是返回false,那么表示先手必胜。
然后如果使用题目的中1000步来做限制,那么会TLE,然后经过测试发现并不需要这么大,200也是可以过的。
这个题目用到了必胜和必败状态的推导。
class Solution {
public:
int dp[10][10][10][10][200][2];
vector<string> Grid;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int clen,mlen,rows,cols;
bool dfs(int sx,int sy,int gx,int gy,int step,int cur){
int &ans = dp[sx][sy][gx][gy][step][cur];
if(ans!=-1) return ans;
if(step>=199) return ans = cur;
if(cur==0){
if(!dfs(sx,sy,gx,gy,step+1,1)) return true;
for(int i=0;i<4;i++){
for(int j=1;j<=mlen;j++){
int tx = sx + dx[i]*j;
int ty = sy + dy[i]*j;
if(tx<0||ty<0||tx>=rows||ty>=cols) break;
if(Grid[tx][ty]=='#') break;
if(Grid[tx][ty]=='F') return ans = true;
if(tx==gx&&ty==gy) continue;
if(!dfs(tx,ty,gx,gy,step+1,1)) return ans = true;
}
}
return ans = false;
}
else{
if(!dfs(sx,sy,gx,gy,step+1,0)) return true;
for(int i=0;i<4;i++){
for(int j=1;j<=clen;j++){
int tx = gx + dx[i]*j;
int ty = gy + dy[i]*j;
if(tx<0||ty<0||tx>=rows||ty>=cols) break;
if(Grid[tx][ty]=='#') break;
if(Grid[tx][ty]=='F') return ans = true;
if(tx==sx&&ty==sy) return ans = true;
if(!dfs(sx,sy,tx,ty,step+1,0)) return ans = true;
}
}
return ans = false;
}
}
bool canMouseWin(vector<string>& grid, int catJump, int mouseJump) {
Grid = grid;
clen = catJump,mlen = mouseJump;
rows = grid.size(),cols = grid[0].length();
int sx,sy,gx,gy;
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(grid[i][j]=='M') sx = i,sy = j;
if(grid[i][j]=='C') gx = i,gy = j;
}
}
memset(dp,-1,sizeof(dp));
bool flag = dfs(sx,sy,gx,gy,0,0);
bool ans;
if(flag) ans = true;
else ans = false;
return ans;
}
};