zoukankan      html  css  js  c++  java
  • 高级软件工程第二次作业

    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("
    ");
    	}
    
    	FILE *f; //将生成数独写入文件
    	f = fopen("shudu.txt","ab+");
    	if (f == NULL)
    	   {
    		  printf("文件打开失败!
    ");
    		  return;
    	    }
    	else
    	{
              for (i = 0; i < 9; i++)
    	      {
    		     for (j = 0; j < 9; j++)
    		      {			
    				  fprintf(f, "%d", grid[i][j]);		
    	        	}	
    			 fprintf(f,"
    ");
           	}
    		  fprintf(f, "
    ");
    	}		
    	 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("
    ");
    			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中必须先进行设置,如下

  • 相关阅读:
    Java学习笔记之——break 和continue
    Java学习笔记之——循环语句
    Java学习笔记之——switch-case条件结构
    Java学习笔记之——if条件语句和三目运算符
    Java学习笔记之——变量与数据类型、运算符
    supervisor-program配置
    应用节点使用管理节点做代理访问互联网的方法
    运营商-技术问题汇总
    galera cluster,mysql配置wsrep_notify_cmd参数,增加邮件告警
    while循环中出现ssh导致读取文件错误
  • 原文地址:https://www.cnblogs.com/wlf123/p/7639385.html
Copyright © 2011-2022 走看看