解题思路——生成数独终局

先来说说数独,数独这个经典的益智游戏,我以前也玩过,我觉得用数独作为个人项目的题目还挺有意思的。

数独的棋盘是一个9×9的格图,每3×3又是一个9宫格。

数独的要求是每行、每列、每个9宫格中,1~9这9个数字必须出现且仅出现一次。

了解了数独的规则之后,再来看看项目需求,第一个需求是要生成1e6种不同的数独终局。刚开始看到这个要求的时候是懵逼的,但是仔细想了一节课之后,发现了数独终局的算是一些性质吧。

举个例子,先来看一个合法的数独终局

123456789
789123456
456789123
912345678
678912345
345678912
891234567
567891234
234567891

我们发现,对于这个数独终局,从第二行开始,每行分别是第一行右移3、6、1、4、7、2、5、8列的结果。

显然,对于任何一个1~9的全排列,都可以通过这种方式来得到一个终局。

这样就可以获得9!=362880种终局。

但是还要求左上角的格子必须是学号后两位之和mod 9 + 1,这样就只有8!=40320种终局。

我们还可以发现,对于任何一个数独终局的1~3行,我们任意交换这三行的顺序,得到的仍然是一个合法的终局,4~6行和7~9行同理,列也同理。

这样我们又可以在刚刚的基础上,按照这种方法扩展出很多种终局。

由于左上角不能动,我们只交换4~6行中的任意两行或者7~9行中的任意两行,这样在刚刚每种终局就可以变成3!×3!=36种终局,一共1451520种终局,已经超过了1e6,可以满足要求了。

编写代码的时候注意一下别算重了就行。

下面给出我的部分实现:

int shift[9] = { 0, 3, 6, 1, 4, 7, 2, 5, 8 };
for (int i = 0; i < 6 && n; i++)
{
    if (i)
    {
        next_permutation(shift + 3, shift + 6);
        shift[6] = 2, shift[7] = 5, shift[8] = 8;
    }
    for (int j = 0; j < 6 && n; j++)
    {
        if (j) next_permutation(shift + 6, shift + 9);
        char row[10] = "123456789";
        for (int k = 0; k < 40320 && n; k++)
        {
            if (k) next_permutation(row + 1, row + 9);
            for (int r = 0; r < 9; r++)
            {
                for (int c = 0; c < 9; c++)
                    cout << row[(c + shift[r]) % 9] << ' ';
                cout << endl;
            }
            cout << endl;
        }
    }
}

优化之后在我本地生成1e6组数独终局只要10s左右,效率还是很不错的。

欢迎各位dalao指点。

转载于:https://www.cnblogs.com/BIT1120161931/p/8618878.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值