软工个人项目——数独(三)

软工个人项目——数独(三)

前段时间一直在准备考试,数独项目进展比较缓慢,现在继续记录进程。本篇博客主要记录数独解决部分的设计实现和两个模块的汇总及main.cpp的实现。
Github项目地址:个人数独项目
最终代码以github为准

1.Solve_Sudoku.cpp的实现

数独的解决方案有很多思路,我首先想到的是用回溯或者DFS进行解题。这里我先选用了回溯法实现,之后在性能优化阶段可以改用DFS进行对比。
回溯法实现比较常规,一个solve()函数用于处理输入的数独,一个Print()函数用于将解决的终局打印出来。

void Solve_Sudoku(int r, int c)
{
	while (sudoku[r][c] != '0') //找到一个空的数独位置 
	{
		if (c < 8)
			c++;
		else //再来一轮 
		{
			c = 0;
			r++;
		}
		if (r == 9)	//找到了一个答案即9x9数独中没有0,那就是找到了一个解答 
		{
			Found_ans = true;
			return; 
		}
	}

	bool Can_Search = false; //标记回溯算法中当前结点是否可以搜索
	for (int i = 1; i <= 9; i++)
	{
		if (Check_Vis(r, c, i))
		{
			Can_Search = true; //标记可以搜索 
			Set_Vis(r, c, i); //当前结点搜索过 
			sudoku[r][c] = i + '0';
			Solve_Sudoku(r, c);
			if (Found_ans) //剪枝 
				return;
			Can_Search = false;
			Reset_Vis(r, c, i);
			sudoku[r][c] = '0';
		}
	}
}

Print()函数用于打印,同时也方便在main源文件中调用:

void Print()
{
	int pos = 0;
	if (Is_First_Task == false) //如果不是第一个问题,就在求解之前输出一行空行 
		OutputFileSolveSudoku << endl; //输入
	else
		Is_First_Task = false;
	for (int i = 0; i < 9; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			if (j != 9)
			{
				Solve_data[pos++] = sudoku[i][j];
				Solve_data[pos++] = ' ';//存入空格	
			}
			else
				Solve_data[pos++] = sudoku[i][j];
		}
		Solve_data[pos++] = '\n';//存入换行符
	}
	OutputFileSolveSudoku << Solve_data; //一个数独终局整体以字符串的形式输出
}

这里吸取了生成终局实现时的经验,直接开了一个大数组进行存储,方便读取写入,减少运行时间。

代码汇总 main.cpp的实现

完成了终局生成和数独求解两个分别的模块后,我开始对这两个模块进行汇总,通过main.cpp实现统一输入、分别调用。
main.cpp只包含main函数。首先通过

FILE* fp1 = fopen(argv[2], "r");

获取输入命令,然后对输入命令进行判断。如果是求解数独但指向文件为空,显示“非法输入!”,如果输入为生成终局,按72为一轮调用sudoku_generate.cpp依次生成;如果为求解数独,则使用fgets()将数独读入到buffer数组中,再调用solve函数依次处理。

int main(int argc, char* argv[])
{
	FILE* fp1 = fopen(argv[2], "r");
	if (strcmp(argv[1], "-s") == 0 && fp1 == NULL)
	{
		printf("非法输入!\n");
		return 0;
	}
	if (argc == 3 && strcmp(argv[1], "-c") == 0)
	{
		int len = strlen(argv[2]); //将命令行字符串转换为整数 
		for (int i = 0; i < len; i++)
		{
			if (argv[2][i] >= '0' && argv[2][i] <= '9')
			{
				int value = argv[2][i] - '0';
				for (int j = 1; j <= len - 1; j++)
					value *= 10;
				n += value;
			}
			else
			{
				printf("Please input a legal number!\n");
				return 0;
			}
		}
		if (n > 1000000 || n <= 0)
		{
			printf("Please input a number from 1 to 1000000!\n");
			return 0;
		}
		int round; //需要生成数独终局的轮数,一轮生成72个
		if (n <= 72)
			round = 1;
		else
			round = n / 72 + 1;
		while (round)
		{
			int demand; //每一轮需要生成的矩阵数 
			Initial(); //初始化数独的第一行 
			if (round != 1) //不是最后一轮 
				demand = 72;
			else //是最后一轮 
				demand = n % 72;
			Produce_Sudoku(demand);
			--round;
		}
	}
	else if (argc == 3 && strcmp(argv[1], "-s") == 0)
	{
		char buf[110];
		int count = 0;
		while (fgets(buf, 20, fp1))
		{
			if (strcmp(buf, "\n") == 0) //遇空行跳过 
				continue;
			for (int i = 0; i <= 16; i++)
			{
				if (i % 2 == 0)
				{
					a[count][i / 2] = buf[i];
					Set_Vis(count, i / 2, buf[i] - '0');
				}
			}
			count++;
			if (count == 9)
			{
				Found_Ans = false;
				Solve_Sudoku(0, 0); //回溯解数独 
				Print();
				memset(vis, 0, sizeof(vis));
				count = 0;
			}
		}
	}
	else
		printf("非法输入!\n");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值