m*n拼图自动还原算法

引言       
          拼图游戏很适合休闲放松的时候玩,所有在上大学的一段时间里,我比较喜欢玩用以打发无聊的时光。
         恰巧2016年李世石与阿尔法狗对弈,虽然不懂围棋,但是围棋对弈作为还未被计算机算法攻陷的堡垒,我很好奇最后结果是什么样,于是就看了每一场比赛。比赛最后的结果与李世石和围棋大师们的预期相反,李世石1:4阿尔法狗宣告计算机获得了胜利。当时我想既然下围棋都能够用算法完成,那么可不可以写一个自动还原拼图的算法呢?我并不懂人工智能,但是还原拼图也是一件很简单的事情,应该能够写成算法。然后我就着手进行了研究,经过一个多月心里也有了一个完整的可行想法。研究做完后由于快要期末了,有很多期末实验要做,也就没有真正的去实现它。现在到了2017年,找了点时间对这个问题进行了更深入的研究,也觉得既然心里有一个不错的想法分享出来会更好。
     
                    
                       打乱前                                         打乱后
人复原拼图的思路
       以4*4拼图为例,说明复原拼图的一般方法,分别对拼图中的图片及位置进行编号。这样我们就能用二元向量来表示某一块图片当前所对应的坐标了,如下图用向量的形式可以表示为:(1,1)、(2,2)......(16,16)。
      约定:向量的第一个数字代表位置,第二个数字代表图片编号 直接用某一块拼图图片的编号作为它的名字,例如称编号为1的一块拼图图片为1.

                                                                                            
    在打乱拼图后,按以下步骤进行复原:
                   图1                      图2                    图3                                 图4      
                                             图5                                                                                       图6                                                                                                                                                                               
          
                   图7                         图8                            图9                                  图10
                

       1.打乱拼图后(图1),首先把1复原到位置1(图2),接着把2复原到位置2(图3)。接着要复原3、4,这时不能直接把3复原到位置3,而是需要先把3移动到位置4,把4移动到位置8(图4),同时复原3、4(图5)。对于m*n拼图,在m>=3,n>=3时,我们需要按行复原,每一行的最后两个需要向上面说的同时进行复原。
       2.按复原第一行的方法复原第二行(图6),对于后两行我们需要按列从左到右进行复原,首先把13移动到位置9,9移动到位置10(图7),同时复原13和9(图8).依照同样的方法复原10、14(图9),最后三块随便按照某一方向旋转,如果拼图是可复原的,剩下的三块会自然地回到自己的位置上(图10)。在复原任意拼图的时候最后两行遵循同样的方法。
       既然是复原m*n,自然会有一些特殊情况:m=1,n>1; m>1,n=1; m=2,n=2; m=2,n=3; m=3,n=2 五种特殊情况,如果一个人知道如何复原4*4的拼图,其实他就能复原任何m*n的拼图。如果机器知道如何复原4*4的拼图,那它就不一定知道如何复原其它的拼图,写这篇博客的动因就是寻找一种复原拼图的普适算法(用面向对象的方法实现它),我们在寻找方法之前可以问自己,为什么人可以迅速掌握一个普遍适用的方法?是否可以用数学里的理论去分析它们呢?


寻求数学上的解法

         不可还原拼图: 不可还原拼图

        了解不可还原拼图对我们的探索会有很大帮助。

         可以用向量的形式表示图片与位置的对应,例如(3,4),我们可以这样定义:处于位置3的是图片4。对于拼图以2*3为例:(1,3)、(2,5)、(3,2)、(4,6)、(5,1)、(6,4)这样可以表示出一个打乱时的状态。

        这为我们提供了一些思路,但是有更好的方法来表示拼图的状态。用置换群表示会是这种形式:(1,3,2,5)(4,6),位置1对应3,位置3对应2,位置2对应5,位置5对应1,位置4对应 6,位置6对应4。 每个数字都有两重意义:位置和拼图编号,读者可以上网搜一些置换群的资料,只需很少的知识就能理解上面的表示方法。
       e表示拼图还原时的状态。
       每次移动拼图都能表示为一次置换运算,例如:由(1,3,2,5)(4,6)移动拼图为(1,6,4,3,2,5)可以用群运算表示为(1,4)(1,3,2,5)(4,6)。可以这样理解对换(1,4),位置1和位置4上的图片交换位置,拼图状态的每一次变化都是一次位置的对换。
      2*3的拼图一共存在7种对换, m*n(m>1,n>1)的拼图一共存在 2*m*n-m-n种对换。
      看看复原拼图的过程如何用置换运算表示,以(1,3,2,5)(4,6)为例,按步计算:
              1,(4,5)(1,3,2,5)(4,6)=(1,3,2,4,6,5)    //交换位置4和5图片
              2,(5,6)(1,3,2,4,6,5)=(1,3,2,4,5)             //交换位置5和6的图片,6回到了自己的位置(这里需要说明6是空缺的那一块)
              3,(3,6)(1,3,2,4,5)=(1,6,3,2,4,5)
              4,     (2,3)(1,6,3,2,4,5)=(1,6,2,4,5)
              5,     (2,5)(1,6,2,4,5)=(1,6,5)(2,4)
              6,     (5,6)(1,6,5)(2,4)=(1,5)(2,4)
              7,     (3,6)(1,5)(2,4)=(1,5)(2,4)(6,3)
              8,(2,3)(1,5)(2,4)(6,3)=(1,5)(2,4,3,6)
              9,     (1,2)(1,5)(2,4,3,6)=(1,5,2,4,3,6)
              10,   (1,4)(1,5,2,4,3,6)=(1,5,2)(3,6,4)
              11,   (4,5)(1,5,2)(3,6,4)=(1,4,3,6,5,2)
               12,  (5,6)(1,4,3,6,5,2)=(1,4,3,5,2)
               13,  (3,6)(1,4,3,5,2)=(1,4,6,3,5,2)
               14,  (2,3)(1,4,6,3,5,2)=(1,4,6,2)(3,5)
               15,  (2,5)(1,4,6,2)(3,5)=(1,4,6,5,3,2)
               16,(5,6)(1,4,6,5,3,2)=(1,4,5,3,2)
              17 ,(3,6)(1,4,5,3,2)=(1,4,5,6,3,2)
              18,(2,3)(1,4,5,6,3,2)=(1,4,5,6,2)
             19 ,(1,2)(1,4,5,6,2)=(1,4,5,6)
             20,(1,4)(1,4,5,6)=(4,5,6)
             21, (4,5)(4,5,6)=(5,6)
             22,(5,6)(5,6)=e
        经过22步把拼图复原,这些计算过程模仿了人复原拼图用的方法。

总结

      现在我们已经找到了人复原拼图遵循的普遍方法,又在数学上找到了移动的对应的表示方式,所以到此可以说已经找到了自动复原拼图的算法。拼图的数学上的解法,有一个有意思之处:每个数字都有双重的含义(即表示图片又表示位置)。由于有其他事情我并未真正实现这个算法,在以后的我会先制作一个拼图游戏,然后再去实现它。如果读到这篇博客的人,对这个问题也有兴趣,也可以按照这个思路自己去实现它。

    


               
          
    
     

       


  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值