2019软工个人项目——数独(二)

数独终局生成

Github项目地址:数独

思路分析

一开始我是顺着上周的大致思路想要用随机数实现的,之前没有仔细研究过数独所以不清楚其中的规律。但是当我写到一半的时候突然意识到一个问题,就是这种随机生成很难按一定规则进行分类,从而确定是否会出现重复的情况。如果这样没有条理地生成,后期进行数度破解的时候就会造成很大困难。
我重新观察了一遍一个数独终局并上网查找了一些关于数独终局形成的规则,很多博客和网站也都有各种算法,大致可以分为两种。一种就是随机填充,同时设定一个map二维数组用于检查该九宫格内某一数字是否出现过;另一种则是通过第一行全排列后进行列变换得到不同终局。考虑到老师有要求终局第一行第一列数字是固定的,我决定采用行列变换的方式进行终局生成,同时这种方式也能很好地避免重复情况。

一个正确的数独终局
以上图数独终局为例,假设第一行是固定的(1 2 3 4 5 6 7 8 9),则剩余八行分别是第一行右移了3、6、1、4、7、2、5、8位,算上首行,则是0、3、6、1、4、7、2、5、8位。由此可知,我们可以固定第一行,然后三行为一组进行互换;同时还可以三列为一组,三组列交换。又因为固定了第一个数字,所以我把第一组行和第一组列排除,只对二三组行和列进行交换。
此时我们对生成终局数进行计算:第一行除第一位进行全排列,共:8!=40320种排法,再加上二三组行的交换,一共8!*3!*3!=1451520种,已经超过了老师要求的1000000种终局要求,所以可以不用考虑列的交换了。

具体实现过程

确定了思路后,我开始着手进行具体的代码实现。我初期的思路是用一个专门的行变换函数实现行与行之间的交换,然后用一个CreateSudoku函数进行6*6的循环填充直至生成满足输入数独终局数量的要求。这样在main.cpp中可以直接调用CreateSudoku函数进行数独终局的生成。
实际实现的时候,一开始我发现很难用简短的编程语言实现全排列这一步骤。后来经同学提醒了解到了next_permutation函数。我上网大概了解了一下这个中的函数:
(以下内容为网络资源摘录)
组合数学中经常用到排列,这里介绍一个计算序列全排列的函数:next_permutation(start,end),和prev_permutation(start,end)。这两个函数作用是一样的,区别就在于前者求的是当前排列的下一个排列,后一个求的是当前排列的上一个排列。至于这里的“前一个”和“后一个”,我们可以把它理解为序列的字典序的前后,严格来讲,就是对于当前序列pn,他的下一个序列pn+1满足:不存在另外的序列pm,使pn<pm<pn+1.
对于next_permutation函数,其函数原型为:

 #include <algorithm>
     bool next_permutation(iterator start,iterator end)

当当前序列不存在下一个排列时,函数返回false,否则返回true

解决了全排列问题以后,在编写Create函数时我发现生成一个终局写进一次txt文件很麻烦。上网查询了一些关于写文件的相关方法,我决定开一个数组把生成的数独终局先暂时存放进去,生成完后再一次性写入文件。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值