判断拼图可还原性

对于九宫格拼图,如果随机打乱的话,有50%的概率会出现不可还原的情况。
可以采用求逆序数的方法避免不可还原的情况。

逆序数:即在一个数列中,每两个数构成一个数对,如果数对中左边的数小于右边的数,则此数对是顺序对,如果左边的数大于右边的数,则此数对就是一个逆序对,数列的所有数对中逆序对的总数就是该数列的逆序数。
例: 0, 3, 1, 2 这个数列中,(0,3),(0,1),(0,2)都是顺序对,(3,1)是逆序对,(3,2)是逆序对,(1,2)是顺序对,只有两个数对是逆序对,所以这个数列的逆序数是2。

三阶拼图

在求解拼图的可还原性时需要把空白块去掉,因为空白块是可以自由移动的,计算它的逆序会增加复杂性。
对于 3 x 3 的拼图,把每一个图块标号为 0,1,2,3,4,5,6,7,8,去掉空白块8号后,保证非空白的8块(即标号为0,1,2,3,4,5,6,7的图块)组成序列的逆序数为偶数即可保证拼图可还原。

如上图所示,图①到图②交换了空白块与图块7,逆序数没有变,都为0,图②到图③交换了空白块与图块4,逆序数增加到2,图④的逆序数为2,交换空白块与图块6后变成图⑤的情况,逆序数还是2,再将图块3与空白块交换变成图⑥的情况,逆序数还是2。
从中可以看出,在水平方向交换空白块与其他图块时,整个数列(去掉空白块后)所有数字的顺序是完全不变的,只有在垂直方向上交换空白块与其他块时,某些数字的顺序才会改变,并且只改变了三个数的顺序,如图②到图③,由4,5,6改变为5,6,4,也就是将4往后移动了2个位置,其他数字与这三个数字的相对顺序都是没有改变的,所以数列逆序数的改变取决于这三个数内部的逆序数的变化,而这三个数的逆序数的改变取决于移动的数与另外两个数的大小关系,在这里移动的是4,另外两个数是5与6,都大于4,所以移动4,逆序数将会加2或减2,而图⑤到图⑥,由3,2,4改变成2,4,3,将3往后移动了2个位置,移动的是3,另外两个数是2与4,一个大于3一个小于3,所以移动3之后,逆序数不变,因此我们可以得出结论:每次交换空白块与其他图块时,无论是水平方向还是垂直方向,数列逆序数要么加减2,要么不变,所以三阶拼图的图块标号构成的数列,其逆序数为偶数,这个拼图就是可以还原的

四阶拼图

接下来分析 4 x 4 的拼图,用 0,1,2,…14,15 来标记每一块图块,15为空白块,此处将它去掉。

与 3 x 3 拼图有点不同,4 x 4 的拼图在垂直方向交换空白块与其他图块时,将影响到4个数的顺序变化,也即逆序数将会受到移动的数字与另外三个数的大小关系的影响,三个数都大于或小于移动的数字,那么逆序数会加3或者减3,两个数大而一个数小,或者两个数小而一个数大,那么逆序数会加1或者减1,总之在移动一次时,其逆序数不会改变2,而我们可以确定在还原好的情况下,其逆序数是0,又由于水平方向移动不会影响逆序数,因此我们可以得出结论:其可还原性与空白块所在行有相关性,即对于四阶拼图,空白块在4、2行(行索引为3、1)时,逆序数为偶数才能保证拼图可还原,空白块在3、1行(行索引为2、0)时,逆序数为奇数才能保证拼图可还原。

五阶拼图

5 x 5 拼图与 3 x 3 拼图分析过程类似,在垂直方向上交换空白块与其他块时,影响到5个数的顺序变化,也即逆序数将会受到移动的数与另外四个数的大小关系影响,可能的变化为0、2、4,因此五阶拼图,逆序数由偶数即可保证拼图的可还原性

逆序数计算

计算逆序数的方法可以参考基本排序算法。
以下采用归并排序的思想计算逆序数,时间复杂度为O(NlogN)。

// 判断拼图是否可还原
BOOL CPuzzleDlg::IsReducible(vector<UINT>& vecIndex)
{// 最后一个标号是可以移动的,故计算逆序数时应去掉,3阶时去掉标号8,4阶时去掉标号15,5阶时去掉24vector<UINT> vecIndexCopy = vecIndex;auto itLastIdx = find(vecIndexCopy.begin(), vecIndexCopy.end(), m_nLastCtlIdx);ASSERT(itLastIdx != vecIndexCopy.end());int nLastIndex = itLastIdx - vecIndexCopy.begin();vecIndexCopy.erase(itLastIdx);// 逆序是高等数学里面的概念,即在数列当中某两个数字(每两个数构成一个数对)是前面的数// 大于后面的数,则这个数对的一个逆序对,逆序数即为该数列中逆序对的总数,// 例:0 2 1 3 4 7 5 6,该数列中共有8个数,有7+6+5+4+3+2+1=28个数对,// 其中 (2,1),(7,5),(7,6) 是逆序对,(0,2),(2,3),(1,6)等等都是顺序对,// 所以本数列的逆序数是3// 此处用归并排序的方式计算逆序数int nInversePairs = InversePairsCore(vecIndexCopy.data(), 0, vecIndexCopy.size() - 1);// 如果是3或5阶,逆序数为偶数才能被还原,// 如果是4阶,则需判断空白块所在行数,行索引为0、2时逆序数要为奇数,行索引为1、3时,行索引要为偶数if (m_nLine == 3 || m_nLine == 5) {return (nInversePairs & 1) == 0;} else if (m_nLine == 4) {return ((nLastIndex / m_nLine) & 1) != (nInversePairs & 1);} else {return FALSE;}
}// 计算逆序数
int CPuzzleDlg::InversePairsCore(UINT* pData, int nLeft, int nRight)
{if (nRight - nLeft <= 0) {return 0;}int nMid = nLeft + ((nRight - nLeft) >> 1);int nLeftPairs = InversePairsCore(pData, nLeft, nMid);int nRightPairs = InversePairsCore(pData, nMid + 1, nRight);int nMergeCount = InversePairsMerge(pData, nLeft, nRight);return nLeftPairs + nRightPairs + nMergeCount;
}// 归并排序方法计算逆序数
int CPuzzleDlg::InversePairsMerge(UINT* pData, int nLeft, int nRight)
{int nMid = nLeft + ((nRight - nLeft) >> 1);int* pTemp = new int[nRight - nLeft + 1];int nLeftIdx = nLeft, nRightIdx = nMid + 1, nIndex = 0;int nInversePairs = 0;while (nLeftIdx <= nMid && nRightIdx <= nRight) {if (pData[nLeftIdx] < pData[nRightIdx]) {pTemp[nIndex++] = pData[nLeftIdx++];} else {pTemp[nIndex++] = pData[nRightIdx++];nInversePairs += nMid - nLeftIdx + 1;}}while (nLeftIdx <= nMid) {pTemp[nIndex++] = pData[nLeftIdx++];}while (nRightIdx <= nRight) {pTemp[nIndex++] = pData[nRightIdx++];}memcpy(pData + nLeft, pTemp, sizeof(int) * (nRight - nLeft + 1));delete[] pTemp;return nInversePairs;
};

此处感谢评论区朋友的点评,此文章是在评论区朋友的提示后修改完成的。

源码链接:九宫格拼图源码-Gitee
源码链接:九宫格拼图源码-CSDN资源

九宫格拼图,避免不可还原相关推荐

  1. 九宫格拼图游戏设计,及代码时序问题解决

    目录 1. 需求简述 2. 大方向思路 3. 具体实现思路 4. 问题描述 5. 问题解决 1. 需求简述 需求是一个九宫格拼图的游戏,每两张图都可以随意对换,当拖动图片经过被交换图片时,拖动图片不动 ...

  2. android实现九宫格拼图小游戏

    贴一下效果图 接下来随便用一张图片就好 以下是全代码 自定义View GameView类 import android.content.Context; import android.graphics ...

  3. 九宫格拼图怎么拼?分享两个简单的操作

    日常生活中发朋友圈的时候,小伙伴是不是有很多照片想分享到朋友圈呢?但是因为朋友圈的限制,不能一次全发.有很多朋友发现很多朋友可以把一张图片剪成9格!看起来很棒,那九宫格拼图怎么拼的呢?今天就和大家分享 ...

  4. java设计九宫格拼图软件哪个好用_九宫格拼图软件下载_抖音很火的九宫格拼图软件app下载_易玩网...

    最近抖音里面好多小伙伴都在晒自己的九宫格拼图照片,小编就为您寻找到了这款APP,软件名字就是分图,能够轻松实现九宫格拼图的制作,你可以随时选择九宫格或者二宫格.三宫格.四宫格以及六宫格,轻松一键制作你 ...

  5. 软件工程作业---结对编程の九宫格拼图扩展

    程序下载:九宫格拼图扩展.exe 想必大家都熟悉九宫格拼图,传统的九宫格拼图就是九个格子,而其中有一个是空的,旁边的可以移动到空的位置,然后通过移动来把乱的图片拼成一个完整的图片,看似简单但其中又有技 ...

  6. java编写九宫格拼图游戏_九宫格拼图游戏

    九宫格拼图游戏设计文档 一.综合设计目的.条件.任务和内容要求: 1.设计目的 <Windows程序设计>是计算机科学与技术专业本科生的一门学科基础课程.Windows程序以图形用户界面( ...

  7. VB实现可调节难度的九宫格拼图

    #VB实现可调节难度的九宫格拼图 实现本游戏需要熟练掌握paintpicture函数的应用,如果读者对该函数不熟练,需要读一下前面两篇博客哦 http://blog.csdn.net/wf824284 ...

  8. j2me实现九宫格拼图

    实验要求 九宫格的拼图游戏,上下左右键用来移动,采用贴图实现. 程序思路 将一张图片分成三行三列进行贴图,首先需要打乱顺序,但保证右下角为空白.然后上下左右可以进行图片的移动,将空白处和四周进行交换, ...

  9. java设计九宫格拼图软件哪个好用_十亿人都在拼的拼图软件,这八款最好用

    Hey,各位喵友好,我是33. 作为一个喜欢拍照的人,不仅要熟悉掌控各种美颜滤镜APP,保证自己能随时P好照片发朋友圈,更要让自己的朋友圈也精致起来~ 可是,简单地发图片功效其实是不够滴,(而且万一想 ...

  10. 九宫格拼图游戏初版(练练手)

    最近自己看完了java初级篇,课堂上讲的太少了,有那么一会儿灵感蹦出就写了九宫格游戏,只是初版,有些细节未处理,但整体功能都已实现,贴截图: 程序有三个.class文件,依次是程序主体Nine,图片方 ...

最新文章

  1. centos 6安装 vim
  2. 漫画图解让美国颤抖的5G,到底牛在哪?
  3. 字符字节Base64编码
  4. java delphi aes加密算法_Delphi AES,又一个加密算法例子
  5. java 递归 时间复杂度_递归到底是怎么实现的?它的时间复杂度怎么算?
  6. python字符串垂直输出加循环_将漂亮的soup嵌套循环垂直输出到datafram中
  7. sed -i 单引号中嵌套双引号_【函数应用】IF函数的多层嵌套
  8. HDU2602 Bone Collector【0/1背包+DP】
  9. iis由5.1变成5.0——怎么回事呢
  10. c语言约瑟夫环分析报告,约瑟夫环C语言实现验证报告.doc
  11. html可以转换wps嘛,如何将图文并茂的网页快速转换为WPS或word文档
  12. A ConneR and the A.R.C. Markland-N
  13. html画布创建黑白象棋棋盘,canvas应用——中国象棋棋盘
  14. 固话月租费有望全免 包月套餐将逐步取代座机费
  15. 【网络】计算机网络-数据链路层 Data Link Layer
  16. C语言中常见的%d,%c,%s,%x各代表什么
  17. linux下查看本机IP的两种方法
  18. mapbox控件-@mapbox/mapbox-gl-draw使用(vue3)
  19. MATLAB如何保存高质量大图
  20. egret res资源配置文件分包加载

热门文章

  1. 腾讯防水墙的使用(python_web)
  2. 使用Java+Puppeteer+OpenCV 过腾讯防水墙滑动验证码
  3. input正则邮箱_JS正则表达式验证email邮箱是否正确
  4. 【学习总结】标准日本语(陈述句)
  5. 物理学四大神兽!今分享一些有意思的东西~~
  6. 一行脚本实现远程开机
  7. 03_Unity小窍门100条(下)
  8. 基于docker的redis4.0单机集群搭建
  9. 微分方程和线性代数(先理解一阶微分形式不变性)
  10. 记一次上海银联总部的投标过程