九宫格拼图,避免不可还原

对于九宫格拼图,如果随机打乱的话,有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号后,使0,1,2,3,4,5,6,7这个数列的逆序数为偶数即可。

012012
345345
678768

如上左图,逆序数为0,此即为还原的标准,右图去掉空白块后,数列为0,1,2,3,4,5,7,6,逆序数为1,这是无法变换成左图的顺序的。

计算逆序数的算法很简单,主要是在于理解用逆序数来避免拼图无法还原的方法。

UINT CPuzzleDlg::CalInverseNum(vector<UINT>& vecIndex)
{
    // 最后一个标号是可以移动的,故计算逆序数时应去掉,3x3时去掉标号8,4x4时去掉标号15,
    vector<UINT> vecCpIndex = vecIndex;
    for (vector<UINT>::iterator Iter = vecCpIndex.begin(); Iter != vecCpIndex.end(); Iter++) {
        if (*Iter == m_nLastCtlIdx) {
            vecCpIndex.erase(Iter);
            break;
        }
    }

    // 逆序数是高等数学里面的概念,即在数列当中前面的数大于后面数的组合,
    // 例:0 2 1 3 4 7 5 6,数列中2与1是一个逆序,7与5是一个逆序,7与6是一个逆序
    // 依次计算逆序数为:0+1+0+0+0+2+0+0=3,所以这个数列的逆序数为 3;
    UINT nInverseNum = 0;
    for (UINT i = 0; i < vecCpIndex.size() - 1; i++) {
        for (UINT j = i + 1; j < vecCpIndex.size(); j++) {
            if (vecCpIndex.at(i) > vecCpIndex.at(j)) {
                nInverseNum++;
            }
        }
    }
    return nInverseNum;
}

源码链接:九宫格拼图-MFC源码

    原文作者:九宫格问题
    原文地址: https://blog.csdn.net/weixin_42438777/article/details/84723308
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞