这是谷歌编程大赛的一道问题(现已结束)。如何解决此问题?
注意:如果您有不同于答案中讨论的方法,请分享,以便我们扩展解决此问题的不同方法的知识。
扫雷是一种计算机游戏,在20世纪80年代变得流行,并仍然包含在某些版本的Microsoft Windows操作系统中。这个问题有一个类似的想法,但它并不假设你玩过扫雷。
在这个问题中,你在一个由相同单元格组成的网格上玩游戏。每个单元格的内容最初都是隐藏的。网格中有M个地雷分布在M个不同的单元格中。没有其他单元格包含地雷。你可以点击任何单元格来揭示它。如果揭示的单元格包含地雷,则游戏结束,你输了。否则,揭示的单元格将包含一个介于0和8之间(包括0和8)的数字,该数字对应于包含地雷的相邻单元格的数量。如果两个单元格共享一个角或一个边,则它们是相邻的。另外,如果揭示的单元格包含0,则揭示单元格的所有相邻单元格都会被自动递归地揭示。当所有不包含地雷的单元格都被揭示时,游戏结束,你赢了。
例如,棋盘的初始配置可能是这样的('*'表示地雷,'c'是第一个点击的单元格):
*..*...**.
....*.....
..c..*....
........*.
..........
点击的方格周围没有地雷,因此当它被揭开时,它会变成0,并且它周围8个方格也将被揭开。这个过程继续进行,导致出现以下棋盘:
*..*...**.
1112*.....
00012*....
00001111*.
00000001..
目前,仍然存在未揭示的不含地雷的单元格(用'.'字符表示),因此玩家必须再次点击以继续游戏。
您希望尽快赢得比赛。没有比一次点击更快的方式了。考虑到棋盘的大小(R x C) 和隐藏的地雷数量M,是否可能(虽然不太可能)在一次点击中获胜?您可以选择点击的位置。如果可能,请按照输出部分的规定打印出任何有效的地雷配置和您的点击坐标。否则,请打印“Impossible”。
我的尝试解决方案:
因此,对于解决方案,您需要确保每个非地雷节点都与其他非地雷节点处于3x3矩阵中,或者是3x2或2x2矩阵,如果节点位于网格的边缘,则为0矩阵。因此,任何在零矩阵中的节点都具有所有非地雷邻居。
首先,检查需要的地雷数量或空节点数量是否较少。
if(# mines required < 1/3 of total grid size)
// Initialize the grid to all clear nodes and populate the mines
foreach (Node A : the set of non-mine nodes)
foreach (Node AN : A.neighbors)
if AN forms a OMatrix with it's neighbors, continue
else break;
// If we got here means we can make A a mine since all of it's neighbors
// form 0Matricies with their other neighbors
// End this loop when we've added the number of mines required
else
// We initialize the grid to all mines and populate the clear nodes
// Here I handle grids > 3x3;
// For smaller grids, I hard coded the logic, eg: 1xn grids, you just populate in 1 dimension
// Now we know that the # clear nodes required will be 3n+2 or 3n+4
// eg: if a 4x4 grid need 8 clear nodes : 3(2) + 2
For (1 -> num 3's needed)
Add 3 nodes going horizontally
When horizontal axis is filled, add 3 nodes going vertically
When vertical axis is filled, go back to horizontal then vertical and so on.
for(1 -> num 2's needed)
Add 2 nodes going horizontally or continuing in the direction from above
When horizontal axis is filled, add 2 nodes going vertically
例如,假设我们有一个4x4的网格,需要8个干净节点,下面是步骤:// Initial grid of all mines
* * * *
* * * *
* * * *
* * * *
// Populating 3's horizontally
. * * *
. * * *
. * * *
* * * *
. . * *
. . * *
. . * *
* * * *
// Populating 2's continuing in the same direction as 3's
. . . *
. . . *
. . * *
* * * *
另一个例子:需要11个空节点的4x4网格;输出:
. . . .
. . . .
. . . *
* * * *
另一个示例:需要14个清晰节点的4x4网格;输出:
// Insert the 4 3's horizontally, then switch to vertical to insert the 2's
. . . .
. . . .
. . . .
. . * *
现在我们有一个完全填满的网格,如果我们点击 (0, 0),就能够在一次点击内解决它。
我的解决方案适用于大多数情况,但是它没有通过提交(我已经检查了整个225个案例的输出文件),所以我猜它存在一些问题,并且我相信有更好的解决方案。