zoukankan      html  css  js  c++  java
  • 自动扫雷 分析

    一.“影响区域”划定

    如上图,假如这个局面摆在我们的面前了。只有红线圈定的内部区域里面的未被挖开的方块才可能被当前局面直接影响。只有在红线圈定区域内的方块确定后,其他区域的未被挖开的方块含有的雷数才能由雷的总数做减法求得。所以我们应该先尽可能的确定红色区域内部雷的分布情况。

    顺便写几个有用的提示:红色区域内部的雷数是有多种可能的;红色区域内部每个方块有雷情况,有的可以精确地推出,有的不能精确推出,只能给个概率值了;最后红线外部每个方块有雷的概率是一样的。

    二.算式推理技术

    对影响区域每一位置都赋予一个符号名,或叫变量名,进行“算式推理”。对于下图的局面(called by 局面1):


    根据每个数字可以列出一个算式,总共得到3个算式:

    a+b=1;

    e+d=1;

    a+b+c+d+e=2; 约束条件是a,b,c,d,e,f取0-1值。

    对于下面的这个图(局面2):


    根据每个数字可以列出一个算式,总共得到4个算式:

    a+b=2;

    a+b+c=2;

    d+e=2;

    b+c+d+e+f=3;约束条件是a,b,c,d,e,f取0-1值。

    “算式推理”指得是由原始的算式集合S0(这里是4个算式)尽可能多的推出算式中符号的确定取值。具体的算法如下:

    1.             若算式集合S0中含有类似局面2中a+b=2 这样的算式,即符号数目和等号右边的数字相等,那么可以确定每个符号的值为1,然后把确定的符号的值给S0中的其他算式中的该符号赋值,如此还可能出现类似c=0这样的算式(对局面2带入a=1,b=1),即左边一些符号相加后得0,那么也可以确定此类算式中每个符号取值0。不断寻找集合S0中的所有类似上面两种情况的算式,确定一些符号的取值,直到集合S0中没有类似的算式。此时得到的算式集合称作S0’。局面1,S0最后化简得到的S0’集合为:

             a+b=1;

    e+d=1;

    a+b+c+d+e=2;约束条件是a,b,c,d,e,f取0-1值。

    局面化简后得到的是a=1,b=1,c=0,d=1,e=1,f=0。这两个例子举得不好,第一个没有得到化简,第二个全化简完了。

    2.             对S0’中的每两个式子之间做检测,若其中某个式子左边的符号是另一个式子左边符号的子集,那么这连个式子相减得到一个新的式子,并加入S0’。

    如,局面1通过这个过程可以得到:

    a+b=1;

    d+e=1;

    a+b+c+d+e=2;

    c+d+e=1;

    a+b+c=1;

    把S0’看做S0,转到第一步继续计算。直到集合不再能推出符号的确定值,也不能产生新的算式为止。

    这个算法最终得到的是一些符号的确定取值,还有一些不能“消融”的式子集合,把它叫做集合St。

    下面给出局面2完整的演算过程:

    1.a+b=1;e+d=1;a+b+c+d+e=2;(步骤一结果)

    2.a+b=1;d+e=1;a+b+c+d+e=2;c+d+e=1;a+b+c=1;(步骤二结果)

    3. a+b=1;d+e=1;a+b+c+d+e=2;c+d+e=1;a+b+c=1;(步骤一结果)

    4.a+b=1;d+e=1;a+b+c+d+e=2;c+d+e=1;a+b+c=1;c=0;( 步骤一结果,每次只要两两检测上一轮新产生的算式和原来的算式就可以,而且有重复的话只留一个就可以)

    5.a+b=1;d+e=1;a+b+d+e=2;c=0(步骤一结果,同样也要去重)

    6.a+b=1;d+e=1;c=0(终止)

    算式推理应该是线性代数里面的线性方程的求解或者数论里面的不定方程求解,肯定还有理论和实现上的优化,由于数学基础较差,只能做到这里了。

    三,枚举手段

    经过“算式推理的过程”,现在我们手头有一些符号确定了,还有一些符号不确定但是他们之间的约束集合St是有的。接下来对于不确定的符号我们只能算出他们有雷的概率了。

    为了编程实现的方便,我们可以采取回溯+枚举这种手段。假设还有a1,a2,…,an 这些符号还没确定,b1,b2,…,bm这些符号确定了。我们采用递归实现枚举a1,…,an取0-1的每种可能,中间结合不确定符号的约束关系做剪枝。最终枚举出来的可能情况假设如下:

    1110101011010….101   91

    1010100101010….100   98

    1111100010100….111   91

    1000011101010….101   89

    前面那个01阵是枚举结果,第i行j列表示第i个枚举中第j个未知符号是否有雷,最后一列是用雷的总数减去红线区域内部的类的数目得到的红线外部的雷的数目。假设总共k个枚举结果,根据枚举结果我们可以统计出每个符号有雷的概率---用该符号位置是1的枚举结果数目除以总的枚举结果数目。

    至于红线外部的方块,他们的有雷的概率都是一样的。我们只能知道该区域含有雷的数目,至于他们怎么分布那就随便了。这个概率的计算可以考虑全概率公式。设枚举结果有100个91,110个90,106个89,105个93,红线外部有M个方块,我认为可以如下计算红线外部每个方块有雷的概率:

    100+106+110+105=421

    P=(100/421)*(91/M)+(110/421)*(90/M)+(106/421)*(89/M)+(105/421)*(93/M)

       

    经过”影响区域”划定,“算式推理”,枚举手段,我们能够精确确定没挖掘方块中的一些是否有雷,以及不能确定的方块的有雷概率。我们把确定没雷的都挖开,再使用上面的手段,再挖雷,直到有一个局面我们不能精确确定任何一个方块,只有概率可以参考,那就只能选个概率小的碰运气了。

    至于程序实现,目前没时间。唯一担心的就是那个枚举太耗时间了,然后有些资料上采用了排列组合的方法计算一个局面的每个方块的有雷情况,如《编程之美——4.11 扫雷游戏的概率 - fivedoumi的专栏 - 博客频道 – CSDN》。但是这种手段只是针对一个很简单的局面在稿纸上做个分析而已。至于情况变复杂,这么多数字之间肯定是有影响的,还不知道怎么算呢,要是再编程实现就更困难了。若是这种采用排列组合来算概率的手段得到很好的推到优化,计算速度肯定大幅提升,但是没时间考虑这些呢!

    最后我发现扫雷游戏的初始局面要不是你中雷,要么是点中一个8邻域无雷的方块得到如下局面:

    要么是你点中一个8邻域内有雷的方块,得到如下局面:


    对于第二种情况,我们用宽度优先搜索呈现给玩家出事局面!


  • 相关阅读:
    累加和最大化
    SELECT子句顺序
    Linux命令入门教程
    求字符串前缀最长的连续重复子串(不重叠)
    王道机试指南题解(C/C++版)
    C++ Primer 第 5 版 习题参考答案
    第 16 章
    第 15 章
    第 14 章
    从jvm源码解读Java运行时的类加载
  • 原文地址:https://www.cnblogs.com/james1207/p/3306513.html
Copyright © 2011-2022 走看看