软工大作业个人项目——数独

本文介绍了一种高效生成大量不重复数独终局的方法,通过全排列和行列变换生成超过100万个数独终局,同时采用回溯法解决数独问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目地址

GitHub项目地址:https://github.com/julianyong/personalpro.git

PSP

PSP2.1Personal Software Process Stage预估耗时(分钟)实际耗时(分钟)
Planning计划
·Estimate·估计这个任务需要多少时间60
·Development开发
·Analysis·需求分析(包括学习新技术)600
·Design Spec·生成设计文档120
·Design Review·设计复审(和同事审核设计文档)0
·Coding Standard·代码规范(为目前的开发制定合适的规范)120
·Design·具体设计180
·Coding·具体编码300
·Code Review·代码复审60
·Test·测试(自我测试,修改代码,提交修改)300
·Reporting·报告180
·Test Report·测试报告60
·Size Measurement·计算工作量30
·Postmortem&process Improvement Plan·事后总结并提出过程改进计划30
合计2040

思路

针对任务的第一个功能——生成N个不重复的数独终局,我最初的想法是通过回溯法暴力生成终局,但是由于最多可生成1000000个数独终局,回溯法无疑会耗费大量的时间,因此我又在网上搜索了相关的生成数独终局的方法。最终选择套用已生成的数独终局模板,通过对1~9进行全排列和数独行列之间的顺序变换生成数独终局。那么使用此方法能否保证可生成的数独终局数量大于1000000且不重复呢?
首先贴出我套用的数独模板

ighcabfde
cabfdeigh
fdeighcab
ghiabcdef
abcdefghi
defghiabc
higbcaefd
bcaefdhig
efdhigbca

接下来生成1到9的全排列序列,并分别将a到i与1到9对应起来,由于要求数独左上角的数字固定为(8+9)%9+1 = 9,因此将i与9对应,a到h与1到8对应起来。只需生成1到8的全排列,共有:1×2×3×4×5×6×7×8 = 40320种对应方法。通过观察不难发现将数独的第2、3行互换,第4、5、6行互换,第7、8、9行互换之后数独仍然符合规则且不重复,因此接下来在一种数字-字母的对应方式下,通过行顺序变换能产生1×2×1×2×3×1×2×3 = 72种不同的数独终局。采用这种方法一共可以产生2903040(大于1000000)种不重复的数独终局,符合题目要求。
解数独则采用了回溯的方法求解。

设计实现过程

使用VS2015自动生成的类图如下:
在这里插入图片描述
核心代码包括生成数独终局的函数int create_Sudoku(int n)和解数独函数void solve_Sudoku(FILE *fp)。
生成n个不重复的数独终局时首先judge_Num(n)函数判断n的合法性,接下来调用int create_Sudoku(int n),函数int create_Sudoku(int n)需要一些辅助函数,比如:void Initial()初始化origin存入以9开头的1~9的全排列序列,void creatModel(MAP &m, int n)根据已有模板针对不同的全排列序列生成盘面,void print(MAP m, int flag)以盘面为单位将数独终局输入到文件。
解数独时调用solve_Sudoku(FILE *fp)比如:bool isPlace(int count, MAP &m) 判断赋值是否符合数独规则,void backtrace(int count, MAP &m) 回溯求解数独终局,void print(MAP m, int flag)以盘面为单位将数独终局输入到文件。

测试

生成数独终局,当输入合法时:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

输入N不合法时:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输入的存储数独题目的文件地址不正确时
在这里插入图片描述
输入合法时
在这里插入图片描述

性能分析

生成数独终局:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由图可知在生成数独终局的过程中消耗最大的函数是向文件中输出数独终局的print()函数。
解数独:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可知占用最高的函数是回溯函数(回溯过程中需要进行输出),实际上仍是输出占用大部分时间

代码说明

生成数独终局

int create_Sudoku(int n)//生成n个不重复的终局
{ 
	fout.open(filepath, ios::trunc);
	int count = 0;
	MAP m;
	if (origin[0][0] == 0) {//如果origin未初始化,则对origin初始化存入全排列序列
		Initial();
	}
	for (int i = 0; i < 40320; i++) {
		memset(m.map, 0, sizeof(m.map));
		creatModel(m, i);//根据字母-数字对应关系生成数独盘面
		MAP backup;
		for (int j = 0; j < 2; j++) {//实现行顺序变换
			for (int ii = 0; ii < 9; ii++)
			{
				backup.map[0][ii] = m.map[general_1[j][0]][ii];
				backup.map[1][ii] = m.map[general_1[j][1]][ii];
				backup.map[2][ii] = m.map[general_1[j][2]][ii];
			}
			for (int k = 0; k < 6; k++)
			{
				for (int ii = 0; ii < 9; ii++)
				{
					backup.map[3][ii] = m.map[general_2[k][0]][ii];
					backup.map[4][ii] = m.map[general_2[k][1]][ii];
					backup.map[5][ii] = m.map[general_2[k][2]][ii];
				}
				for (int l = 0; l < 6; l++)
				{
					for (int ii = 0; ii < 9; ii++)
					{
						backup.map[6][ii] = m.map[general_3[l][0]][ii];
						backup.map[7][ii] = m.map[general_3[l][1]][ii];
						backup.map[8][ii] = m.map[general_3[l][2]][ii];
					}
					print(backup, count);//以数独盘面为单位输出到文件中
					count++;
					if (count == n)
					{
						fout.close();
						return 1;
					}
				}
			}
		}
	}
	return 0;
}

求解数独

void solve_Sudoku(FILE *fp)//生成并输出填好的数独终局
{
	fout.open(filepath, ios::trunc);
	MAP m;

	int tmp;
	while (~fscanf(fp, "%d", &tmp)) {//从文件中读出数独题目内容
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (i == 0 && j == 0) {
					m.map[i][j] = tmp;
				}
				else {
					fscanf(fp, "%d", &m.map[i][j]);
				}
			}
		}
		backtrace(0, m);//回溯解数独
		flag = 1;
	}
	fclose(fp);
	fout.close();
}

回溯求解数独

void backtrace(int count, MAP &m) {//回溯求解数独终局
	if (count == 81) {
		print(m, flag);
		return;
	}
	int row = count / 9;
	int col = count % 9;
	if (m.map[row][col] == 0) {
		for (int i = 1; i <= 9; ++i) {
			m.map[row][col] = i;//赋值
			if (isPlace(count, m)) {//检查赋值是否合法
				backtrace(count + 1, m);//递归进入下一层
			}
		}
		m.map[row][col] = 0;//回溯
	}
	else {
		backtrace(count + 1, m);
	}
}

PSP

PSP2.1Personal Software Process Stage预估耗时(分钟)实际耗时(分钟)
Planning计划
·Estimate·估计这个任务需要多少时间6090
·Development开发
·Analysis·需求分析(包括学习新技术)600360
·Design Spec·生成设计文档120180
·Design Review·设计复审(和同事审核设计文档)00
·Coding Standard·代码规范(为目前的开发制定合适的规范)120150
·Design·具体设计180240
·Coding·具体编码300360
·Code Review·代码复审6030
·Test·测试(自我测试,修改代码,提交修改)300300
·Reporting·报告180120
·Test Report·测试报告6060
·Size Measurement·计算工作量3030
·Postmortem&process Improvement Plan·事后总结并提出过程改进计划3030
合计20401950

遇到的问题

在开发过程中遇到了无法创建.txt文件的问题,使用fopen打开文件时,虽然返回值显示已成功打开文件,但在文件资源管理器中却找不到对应的文件。最终选择使用ofstream打开文件解决问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值