leetcode 529.扫雷游戏(DFS)
题目描述
样例描述
算法分析
这个题还是规矩比较多的,尤其是一开始打算用C语言做(本人学习密码编码学,算法工程上都是用C实现,所以刻意练习用C写算法)。一看到那个C语言提交的模板就傻了,那参数多的啊……果断C++写!
好了,废话不多说!
提炼题目描述
给出click的位置,要求问你click之后的游戏面板会变成啥子模样~
如果你不小心点到了雷,那就显示一个 ‘X’ ,游戏自然结束(和扫雷一样~)
否则就需要去处理很多东西了,你想想看,自己玩扫雷的时候,是不是一点就空出来一大片,这就是根据这个算法去处理的。处理的规则是什么呢??
规则1 :
如果你点到的周围有雷,那么就不继续了,只留下八个方向上雷的个数,告诉玩家。
规则2:
如果你点到的八个方向上一个雷也没有,那就由 ‘E’ 变成 ‘B’ 。相当于告诉玩家,你点过了,这也是为何你扫雷游戏有时候一点空出一大片的原因。就是因为这个位置周围没有雷,所以直接显示成 ‘E’ !!
编码实现
好了,规则其实也就这么两点啦,是自己太浮躁一开始没看进去啦~
然后如何编码实现呢?给出一个click的点,然后你可以得到click的行 r 和 列 c,如果这个位置就是雷,那么直接表示成 ‘X’ ,本次 click 结束!否则进入dfs()!
具体怎么去 dfs 呢?首先初始化的面板只有 ‘M’ 和 ‘E’ ,所以能够进入 dfs() 就说明你当前是 ‘E’,所以需要先判断它周围有无雷,有的话,求出有多少,然后此处的位置改成数字即可!改成数字之后这个位置也不需要继续下去了~否则就说明这个位置周围没有雷,就改成 ‘B’,代表是个周围没有雷的,且已经点击过的地方!!然后朝着八个方向去递归,而递归的出口如何处置呢?我们可以设置一个状态记录的数组,如果当前的点是已经处理过的,那就return,就好了!
具体解题代码
class Solution {
public:
int dir[8][2] = {
{
0, 1}, {
0, -1}, {
1, 0}, {
-1, 0}, {
1, 1}, {
1, -1}, {
-1, 1}, {
-1, -1}};
int vis[50][50] = {
0};
void dfs(int x, int y, vector<vector<char>>& board){
if(vis[x][y])
return ;
vis[x][y] = 1;
int cnt = 0;
for(int i = 0;i < 8;++i){
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if(dx >= 0 && dx < (int)board.size() && dy >= 0 && dy < (int)board[0].size()){
if('M' == board[dx][dy])
cnt++;
}
}
if(cnt > 0){
board[x][y] = cnt + '0';
}
else{
board[x][y] = 'B';
for(int i = 0;i < 8;++i){
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if(dx >= 0 && dx < (int)board.size() && dy >= 0 && dy < (int)board[0].size())
if(!vis[dx][dy])
dfs(dx, dy, board);
}
}
}
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
int r = click[0], c = click[1];
if('M' == board[r][c])
board[r][c] = 'X';
else
dfs(r, c, board);
return board;
}
};
提交的结果
这个性能很不理想啊,希望有提出更好的解决方案的同仁前辈,不吝赐教!
解答一个问题
有很多人会问,为何样例的正上方还有一个 ‘E’ 没有被处理呢??
其实很简单,因为从click的位置出发,在遇到这个 ‘E’ 之前,会遇到周围有雷的位置,遇到这些位置的时候,就会停止递归处理了!所以无法处理这个 ‘E’ ~
其实你去玩扫雷这个游戏,也会发现,人家也就是这么处理的!
写在后面
由于本人能力有限,如果有写错或者有瑕疵的地方,还请各位不吝赐教!希望能够通过留言私信,得到您的指教!