第十七周算法设计与分析:Minesweeper

来源:互联网 发布:什么是出轨渣男 知乎 编辑:程序博客网 时间:2024/06/05 01:17

问题描述:

Let’s play the minesweeper game (Wikipedia, online game)!

You are given a 2D char matrix representing the game board. ‘M’ represents an unrevealed mine,** ‘E’ represents an **unrevealed empty square, ‘B’ represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit (‘1’ to ‘8’) represents how many mines are adjacent to this revealed square, and finally ‘X’ represents a revealed mine.

Now given the next click position (row and column indices) among all the unrevealed squares (‘M’ or ‘E’), return the board after revealing this position according to the following rules:

  1. If a mine (‘M’) is revealed, then the game is over - change it to ‘X’.
  2. If an empty square (‘E’) with no adjacent mines is revealed, then change it to revealed blank (‘B’) and all of its adjacent unrevealed squares should be revealed recursively.
  3. If an empty square (‘E’) with at least one adjacent mine is revealed, then change it to a digit (‘1’ to ‘8’) representing the number of adjacent mines.
  4. Return the board when no more squares will be revealed.

Example 1:
Input:

[[‘E’, ‘E’, ‘E’, ‘E’, ‘E’],
[‘E’, ‘E’, ‘M’, ‘E’, ‘E’],
[‘E’, ‘E’, ‘E’, ‘E’, ‘E’],
[‘E’, ‘E’, ‘E’, ‘E’, ‘E’]]

Click : [3,0]

Output:

[[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘M’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
[‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]

Explanation:
扫雷例子1

Example 2:
Input:

[[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘M’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
[‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]

Click : [1,2]

Output:

[[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘X’, ‘1’, ‘B’],
[‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
[‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]

Explanation:
扫雷例子2

Note:

  1. The range of the input matrix’s height and width is [1,50].
  2. The click position will only be an unrevealed square (‘M’ or ‘E’), which also means the input board contains at least one clickable square.
  3. The input board won’t be a stage when game is over (some mines have been revealed).
  4. For simplicity, not mentioned rules should be ignored in this problem. For example, you don’t need to reveal all the unrevealed mines when the game is over, consider any cases that you will win the game or flag any squares.

问题来自此处


解答思路:
扫雷以前经常玩啦,突然发现有这种题目赶紧来写一波。

题目看起来好长好复杂,不过玩过扫雷的童鞋都大概知道其原理啦。题目简要地说就是要让用户点一个位置,然后通过检测这个位置的类型,程序进行相应的判断和遍历操作,跟扫雷游戏一样~~

程序采用深度优先 (Depth-First) 遍历的方法:

  1. 如果点到了雷 ‘M’,将当前位置改为‘X’并结束函数;
  2. 点到了‘E’(那么此处肯定不是雷):先搜集一下它的四周(3*3个格子)有几个雷——如果有雷,将当前格子改为数字字符;如果周围无雷,那么将当前格子改成‘B’;如果在深度优先遍历中发现自身是雷或者‘B’,则悄咪咪返回,什么都不修改;
  3. 往当前格子的(3*3-1)个方向即左上右上左下右下按顺序进行深度优先遍历,具体操作同2。
class Solution {public:    vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {        if (board[click[0]][click[1]] == 'M') {            board[click[0]][click[1]] = 'X';            return board;        }        update_now(board, click);        return board;    }    void update_now(vector<vector<char>>& board, vector<int>& click) {        int x = click[0];        int y = click[1];        int size = board.size();        if (board[x][y] == 'M') {            return;        }        if (board[x][y] == 'E') {            bool flag = false;            int count = 0;            //搜集周围雷数            for (int i = -1; i <= 1; i++) {                if (x + i >= 0 && x + i < size) {                    for (int j = -1; j <= 1; j++) {                        if (y + j >= 0 && y + j < board[0].size()) {                            if (board[x + i][y + j] == 'M') {                                count++;                                flag = true;                            }                        }                    }                }            }            if (!flag) {                board[x][y] = 'B';            }            else {                board[x][y] = count + '0';                return;//不返回可能会把数字隔壁的'E'也翻开了            }            for (int i = -1; i <= 1; i++) {                if (x + i >= 0 && x + i < size) {                    for (int j = -1; j <= 1; j++) {                        if (y + j >= 0 && y + j < board[0].size()) {                            if (!(i==0 && j==0)){ //这个判断写错就太蛋疼了。。。明明只想要不遍历它自身                                click[0] = x + i;                                click[1] = y + j;                                update_now(board, click);                            }                        }                    }                }            }          }      }    };

算法的空间复杂度为O(MN),时间复杂度为O(MN)

。。。

好了补完上周的啦~
BOOM

原创粉丝点击