高级软件工程第二次作业

1)GitHub项目地址
GitHub地址
使用语言:c
运行环境:WIN10
开发平台:Visual Studio Professional 2015
2)预计程序耗时

3)解题思路描述

   当看到9*9数独题目时,一开始觉得并不难。我首先想到的是做一个3*3的数独,因为我认为可以以小见大,原本是想通过循环实现,但是后面发现还是递归比较靠谱。在做数独的过程中,我百度了很多资料:明白了使用rand前要用srand设置函数,并且因为是要实现多个数独,速度太快,srand会设置出相同的种子;搞清楚了数独的基本做法,要先对行列进行比较,还要比较所在的小九宫格,当试值失败时,还要将值设回初值不影响接下来的测试;也搞清楚了一些被遗忘的基础知识,比如对文件的读写,和防止数据写入的置换等等。虽然自己的基础不稳,但是还是在不停的百度的艰辛过程中完成了此次作业。

4)设计实现
我用一个二维数组来存放所形成的数独,通过判别行列不重复,所在九宫格重复来决定当前位置的取值。当完成某个位置的填值时,递归继续下一个位置或者下一行的第一个位置的填值。当填值失败时,当前位置设置回初值,并返回上一层。
用到了如下几个函数:
- void main() 程序的入口, 在此接受所需的数独个数并且进行输入合法判断,后调用其他函数。
- void generate(int num) 随机生成数独第一行数据的函数。
- bool generateall(int m, int n) 递归函数,在此函数递归完成数独。
- void show() 输出函数,在此将所形成数独输出,并且将其写入棋盘文件
5)代码说明


          bool generateall(int m, int n)
        {
	if (m > 8 || n> 8)//此时数独已完成
		return true;
	int i, j, k;
	for (k = 1; k <= 9; k++)
	{		
		bool flag = true;//flag标记k能否可以放在此位置
		for (i = 0; i<m; i++)
		{		//查询此列是否有相同的数
			if (grid[i][n] == k)
			{
				flag = false;				
				break;
			}
		}
		if (flag)
		{
			for (j = 0; j <n; j++)
			{//查询此行是否有相同的数
				if (grid[m][j] == k)
				{
					flag = false;
					break;
				}

			}
		}
		if (flag)
		{
			//查询所在九宫格是否有相同的数
			int p, q, p1, q1;
			p = m - m % 3;p1 = p + 3; //所在九宫格的行上下限
			q = n - n % 3;q1 = q + 3;//所在九宫格的列上下限
			for (i = p; i <p1; i++)
			{
				for (j = q; j <q1; j++)
				{
					if (grid[i][j] == k)
					{
						flag = false;
						break;
					}
				}
			}
		}
		if (flag)
		{
			grid[m][n] = k;
			if (n < 8)
			{
				if (generateall(m, n + 1)) return true;//到同行的下一列
	
			}
			else
			{
				if (m < 8)
				{
					if (generateall(m + 1, 0))//到下一行的第一列
						return true;
				
				}
				else return true;//此时数独已完成
			}
			grid[m][n] = 0;//当数字1到9都测试失败时,恢复原值
		}

	}

	return false;
      }

        void generate(int num)
      {
	int index = 0, sum = 36, i, j;
	
		srand(num);//设置种子
		for (i = 0; i < 9; i++)
			for (j = 0; j < 9; j++)
			{
				grid[i][j] = 0;//初始化矩阵
			}
		for (int i = 0; i < 8; ++i)//随机产生第一行
		{
			index = rand() % 9;//产生随机数
			while (grid[0][index] != 0)
			{
				index = rand() % 9;
			}
			grid[0][index] = i + 1;
			sum -= index;
		}
		grid[0][sum] = 9;

	}


      void show()
     {
	int i, j;//输出生成数独
	for (i = 0; i < 9; i++)
	{
		for (j = 0; j < 9; j++)
		{
			printf("%d", grid[i][j]);
		}
		printf("\n");
	}

	FILE *f; //将生成数独写入文件
	f = fopen("shudu.txt","ab+");
	if (f == NULL)
	   {
		  printf("文件打开失败!\n");
		  return;
	    }
	else
	{
          for (i = 0; i < 9; i++)
	      {
		     for (j = 0; j < 9; j++)
		      {			
				  fprintf(f, "%d", grid[i][j]);		
	        	}	
			 fprintf(f,"\r\n");
       	}
		  fprintf(f, "\r\n");
	}		
	 fclose(f);
	

     }

     void main()
     {
	char  a[11] = { 0 },b; 
	int flag = true,i,k=0;
	scanf("%s",&a);	

	for ( i = 0; a[i]!=0; i++)
	{
		
		if (a[i]< 48 || a[i] > 57)
		{
			printf("输入有错!"); flag = false; break;
		}
		else { k = k * 10 + (a[i]-48);
		}
	}
	
	if (flag)
	{
		while (k)
		{
			printf("\n");
			generate(k);
			generateall(1, 0);
			show();
			k--;
		}
		
	}
	
	system("pause");
     }

6)测试运行

7)性能分析
当测试数据为4000时:

如报表所示:因为本身将4000个数独写入文件的同时输出到屏幕,所以实现此功能的show函数占用的cpu很大;因为耗时比单单写入文件久,这一点由printf所占用的cpu就可以看出;
于是将输出到屏幕的代码注释,输入值还是4000时,得出如下报表:

可以看出时间上的明显缩短,由1:14分钟缩短为7.257秒,并且大部分函数的总CPU都有了大幅度的下降。

自己实现的这个代码是采用递归,本质上是采用最简单的暴力破解,但是能力有限,没有办法采用较好的方法。

8)实际程序耗时

9)备注
因为代码中使用了fopen,所以vs中必须先进行设置,如下

posted @ 2017-10-09 08:59  小怪兽1  阅读(162)  评论(2编辑  收藏  举报