(2)PSP表格:
(3)解题思路:
1.刚拿到题目的时候,因为之前没有接触过数独类型的问题,题目要求输出n个数独,因此我先从输出一个数独入手。
2.脑子里第一想到的是用随机数,在数独左上角的数确定之后,对剩余的空格依次用随机数按序插入,插入的同时进行检测(所在行,所在列,所在宫是否有相同的数字),在将数独填充完成后输出。但是之后我认为该方法在随机数的使用上太过繁琐,且无法保证输出多个数独时没有重复,因此放弃。
3.之后和同学交流,得知他使用的是深度优先搜索,也就是回溯法。大致思路是先确定一个数独,再从该数独的最后一个填入数字往回尝试不同的可能并输出结果。但是我个人对深度优先搜索不是非常熟练,一时没有很好地理解这种解题方法,因此我选择上网查找其他的方法。
4.在网上查找解题方法时,我看到了这种解法:http://blog.csdn.net/peng_wu01/article/details/6026103。 该解法相当巧妙,原理是使用一个原始数独与一组由随机数算法生成的范围1~9无重复的数,原始数独通过随机数组进行变换,变换的规律为:依次遍历原始数独中的每一个数,将该数替换为随机数组中该数后一个位置上的数。一共能生成的随机数组有9!个,因此一个原始数独能变换出9!即362880个新数独,因此只要找到4个独立的原始数独,就能通过变换达成题目要求的1000000个数独的数量。
5.后来看到题目要求输出的数独的左上角固定(为学生个人学号最后两位的和+1),因此必须保证原始数独的左上角经过变换后是7(我的学号后两位为24),所以在找寻独立的原始数独时,必须避开左上角是7的原始数独(无法通过上述规律进行变换),并且要确保原始数独左上角的数在随机数组中后一位的数是7(这样才能保证变换出的新数独左上角是题目要求的7),而加以限制之后,一个原始数独只能变换出8*7!=8!=40320个新数独,所以达成题目要求的1000000个数独数量所需要的原始数独数量达到了25个。(汗)
7.随机数算法是这道题目中的重中之重,因为我之前从未使用过随机数算法,于是我花了一些时间查阅相关资料并做了独立的随机数实验。网络上的算法基本上都是使用系统时间作为生成随机数的种子,期间我遇到了多次随机的结果相同的现象,几经周折后明白定义随机数的种子一整个代码中只需做一次就可以了……
(4)设计实现:代码结构较为简单,大致由以下几部分组成:
1.随机数算法:直接使用网上的算法,需要理解的问题主要有:
1.生成多少个随机数
2.生成随机数的范围
2.原始数独录入:使用一个三维数组进行录入。
3.变换数独算法:将原始数独中每个数字经过变换后得到的数字赋予一个新的二维数组对应位置,原始数组保留不做变换。
4.变换后数独的输出:用一个二次循环进行打印。
5.以文件形式输出:使用freopen头文件。
(5)代码说明:
include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int u;
scanf("%d",&u);
int list[9], i,j,k,l,a,b;
int x,t;
srand(time(NULL));//设置随机数种子。
int sudo[4][9][9]=
{
{
{9,1,5,2,8,6,4,3,7},
{2,8,7,9,3,4,6,1,5},
{4,6,3,7,5,1,9,2,8},
{8,3,4,5,7,9,2,6,1},
{1,2,6,8,4,3,7,5,9},
{7,5,9,6,1,2,8,4,3},
{6,9,8,1,2,5,3,7,4},
{5,4,2,3,9,7,1,8,6},
{3,7,1,4,6,8,5,9,2},
},
{
{3,8,2,1,6,9,4,7,5},
{1,7,4,3,5,2,6,8,9},
{9,6,5,4,7,8,3,1,2},
{7,3,8,5,1,6,2,9,4},
{5,9,1,2,3,4,7,6,8},
{2,4,6,9,8,7,5,3,1},
{4,1,9,7,2,3,8,5,6},
{8,5,3,6,4,1,9,2,7},
{6,2,7,8,9,5,1,4,3},
},
{
{4,3,7,1,6,2,9,5,8},
{5,2,8,3,4,9,1,6,7},
{6,1,9,7,5,8,3,2,4},
{3,5,2,4,9,1,8,7,6},
{9,8,4,5,7,6,2,3,1},
{7,6,1,8,2,3,4,9,5},
{1,4,6,9,3,7,5,8,2},
{8,7,3,2,1,5,6,4,9},
{2,9,5,6,8,4,7,1,3},
},
{
{2,9,6,5,8,7,3,1,4},
{8,3,5,9,4,1,2,6,7},
{4,7,1,3,6,2,9,8,5},
{9,1,4,8,7,5,6,2,3},
{7,8,2,6,1,3,5,4,9},
{5,6,3,2,9,4,1,7,8},
{3,4,7,1,2,9,8,5,6},
{1,5,8,7,3,6,4,9,2},
{6,2,9,4,5,8,7,3,1},
}
};//录入独立原始数独。
for(l=1;l<=u;l++)
{
b=rand()%3;//获取一个0~3之间的随机数,选择原始数独。
for(i=0;i<9;i++)
{
while(1)
{
a=rand()%9+1; //获取一个1~9之间的随机数。
for(j=0;j<i;j++)
if(list[j]==a)
break;//检查重复。
if(j==i)//没有重复值,保存到list中。
{
list[i]=a;
break;
}
}
}//得到一个随机数组
x=sudo[b][0][0];//将原始数独左上角的数提取 。
for(i=0;i<9;i++)
{
if(list[i]==x)
{
t=list[(i+1)%9];
break;
}
}// 在随机数组中获取原始数独左上角数的位置,并得到其下一位置的数。
for(j=0;j<9;j++)
{
if(list[j]==7)
{
list[j]=t;
list[(i+1)%9]=7;
break;
}
}//将随机数组中原始数独左上角数下一位置的数与题目要求的数进行位置互换。
int prt[9][9];//定义一个二维数组,临时保存变换后的新数独以及输出新数独。
int y;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{
y=sudo[b][i][j];
for(k=0;k<9;k++)
{
if(list[k]==y)
{
prt[i][j]=list[(k+1)%9];
}
}
}//用二维数组存储变换后的数独。
for(i=0;i<9;i++)
for(j=0;j<9;j++)
{
printf("%d ",prt[i][j]);
if(j==8)
printf("
");
if(j==8&&i==8)
printf("
");
}//打印变换后的数独。
}
return 0;
}
(6)测试运行:
(7)性能测试:
关于执行力和泛泛而谈的理解:
1.我认为执行力是接受一个任务(命令,信号)后,对其的反应速度。比如在团队向游戏中,一个玩家在收到队友的信息反馈后,如果能迅速地配合队友行动,往往能创造良好的取胜机会,职业选手和业余选手在这方面上有很大的区别。该点在团体体育项目中同样适用。
2.我认为泛泛而谈指在谈论一件事物时,不结合该事物的时间、空间等具体情况。最典型的莫过于生活中大家常说“等一会”,可“一会”具体又是几分钟,并没有详细的定义。
一些遇到的其他的小问题以及解决方法:
1.markdown的插入代码,如果代码格式不规范可能会造成代码块断断续续,可以使用stackedit:https://stackedit.io/ ,进行markdown文本编辑与浏览,在stackedit上完成代码规范化后再将代码复制回博客编辑器。
2.在github的使用上遇到了一些问题,不过所有情况都可以通过百度查到解决方案。