个人项目-数独

一.github地址https://github.com/yuweijianqqq/shudu
二.PSP表格
在这里插入图片描述
三.思路分析
这个问题分为两部分。第一部分是数独的生成,另一部分是数独的解答。

(1).数独生成
数独的每一行,每一列,每一个33小九宫格都要出现1到9,并且不能够重复。通过对数独的了解和查阅资料,发现了一种有效生成数独的方法。数独可以通过平移第一行一定的列数来生成,使用这种方法的原理是:第一行出现了1到9且不重复,因此后面的每一行都不重复;每一次平移的数不同,因此每一列都会出现1到9不重复的数;毎三行平移都采用以3为间隔,这样就可以保证每个33小九宫格都出现1到9且不重复。下面举一个例子:
712345689
345689712
689712345
123456897
456897123
897123456
234568971
568971234
971234568
因此我们可以通过数独的第一行来生成一个数独。因为第一个数字固定,因此第一行的排列有8!个。由于数独的每三行都可以进行自由的变动,所以又可以在生成的数独产生一种变换方式。由于第一行的第一个数字不能变,因此123行只能有2种变动,456和789分别可以有6种变动,总共产生了72种变动方式。72*8!>1000000,已经满足了题目的要求。

(2).数独解答
数独的解答我用了回溯法。回溯的思路是顺序的搜索整个数独,如果这个数没有填入数字,那么在这个位置放一个合适的数,然后继续。如果有一个位置1到9都不满足,那么就向前回溯,继续进行前面的步骤,直到找到一个解为止。

四.实现过程
在数独生成上,具体的实现过程如下:使用了一个shengcheng(int n)函数和一个panduan(char *q)函数,在shengcheng函数中实现生成和输出数独,panduan()函数时对输入进行判断,输入是否为数字,然后在主函数中进行调用即可。
在解数独。使用一个check(int n)函数来判断该位置是否可以放置要放入的数字,使用一个output()函数来实现数独的输出,一个DFS(int n)函数通过对check()函数的调用来实现对数独的解。
在这里插入图片描述

五.性能优化
在最开始,生成1000个数独所花费的时间还比较短,但是当生成1000000个数独的时候。所用的时间就需要几分钟了。 通过VS对代码进行了性能分析,发现了很长一部分的时间用在输出上。每输出一个数独都需要打开和关闭文件。通过改进,我将所有的数独都保存在一个字符串中,这样输出只需要打开和关闭文件一次,减少了大量的时间。
经过改进之后的时间减少到了35秒左右,与之前的几分钟相比有了很大的改进。下面是性能分析图:
在这里插入图片描述
六.测试用例

sudoku.exe -c 1000
sudoku.exe -c 10000000
sudoku.exe -c abc
sudoku.exe -c 1000abc
sudoku.exe -c abc1000
sudoku.exe -c 100000000
sudoku.exe -s jieti.txt
sudoku.exe -n

在这里插入图片描述

七.部分代码展示
1.生成数独的函数

void shengcheng(int n)
{
	m = 0;
	int t=0;
	int s[9] = { 0,3,6,1,4,7,2,5,8 };//行的平移 
	for (int i = 0; i < 2; i++)
	{
		if (i != 0) next_permutation(s + 1, s + 3);//23行变换 
		for (int j = 0; j < 6; j++)
		{
			if (j != 0) next_permutation(s + 3, s + 6);//456行变换?
			for (int k = 0; k < 6; k++)
			{
				if (k != 0) next_permutation(s + 6, s + 9);//789行变换
				char y[9] = {'7','1','2','3','4','5','6','8','9'};//初始行 
				for (int l = 0; l < 40320; l++)
				{
					if (l != 0) next_permutation(y + 1, y + 9);//行之间换 
					for (int b = 0; b < 9; b++)
						d[0][b] = y[b];
					for (int b = 0; b < 9; b++)
					{
						for (int c = 0; c < 9; c++)
						{
							int p = c + s[b];
							d[b][c] = d[0][p % 9];
							if (c == 8&&b<8) 
							{
								w[t++]=d[b][c];
								w[t++]='\n';
							}
							if(c==8&&b==8)
							{
								w[t++]=d[b][c];
								w[t++]='\n';
								w[t++]='\n';
							}
							if(c<8&&b<9)
							{
							w[t++]=d[b][c];
							w[t++]=' ';	
							} 
						}
					}
					m++;
					if (m >= n)
					{
					   Output<<w;
				    	return;
					}
					
				}
			}
		}
	 }
}

2.回溯法解数独

int DFS(int n)
{
	if (sign) return 0;
    if (n>80)
    {
    	output();
		sign=true;
        return 0;
    }
    if(d[n/9][n%9] == 0){
		for(int i = 1; i <= 9; i++)
		{
			d[n/9][n%9] = i;//赋值
			if(check(n))//可以放
			{
				DFS(n+1);//进入下一层
			}
		}
		d[n/9][n%9] = 0;//回溯
	}
	else
	{
		DFS(n+1);
	}
}


八.实际花费的时间
在这里插入图片描述

九.感想
这次的个人项目让我学到了挺多的东西的,不单单是知识上的,也了解了做一个项目所需要的过程和步骤。在做个人项目的过程中也遇到了挺多的问题,但通过查阅资料和同学的帮助,这些问题都得到了解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值