利用程序随机构造N个已解答的数独棋盘
项目需求:利用程序随机构造N个已解答的数独棋盘
输入:数独棋盘题目个数N (0 < N <= 1000000)
输出:随机生成N个不重复的已解答完毕的数独棋盘, 并输出到sudotiku.txt,每个数独棋盘中间隔一行
#include<iostream> #include<cstdlib> #include<ctime> #include<fstream> using namespace std; ofstream ocout; int sudo[9][9]; bool set(int x,int y,int val) { if(sudo[x][y]!=0) //非空 return false; int x0,y0; for(y0=0;y0<9;y0++) //行冲突 { if(sudo[x][y0]==val) return false; } for(x0=0;x0<9;x0++) //列冲突 { if(sudo[x0][y]==val) return false; } for(x0=x/3*3;x0<x/3*3+3;x0++) //格冲突 { for(y0=y/3*3;y0<y/3*3+3;y0++) { if(sudo[x0][y0]==val) return false; } } sudo[x][y]=val; return true; } void current(int* cur) ///0~9随机序列 { int i,j,temp; for(int i=0;i<9;i++) { cur[i]=i; } for(int i=0;i<9;i++) { j=rand()%9; temp=cur[j]; cur[j]=cur[i]; cur[i]=temp; } } void reset(int x,int y) { sudo[x][y]=0; } bool fill(int x,int val) { int cur[9]; current(cur); //生成当前行的扫描序列 for(int i=0;i<9;i++) { int y=cur[i]; if(set(x,y,val)) //可以先把每一行的1填了,再填每一行的2...以此类推 { if(x==8) //到了最后一行 { if(val==9||fill(0,val+1)) //当前填9则结束,否则从第一行填下一个数 return true; } else { if(fill(x+1,val)) //下一行继续填当前数 return true; } reset(x,y); //回溯 } } return false; } void clear(int temp[9][9]) //清空 { for(int i=0;i<9;i++) { for(int j=0;j<9;j++) { temp[i][j]=0; } } } void printsudo() //输出到屏幕 { for(int x=0;x<9;x++) { (x%3==0)?(cout<<" -----------------------\n "):(cout<<" "); cout<<"| "; for(int y=0;y<9;y++) { cout<<sudo[x][y]<<" "; (y%3==2)?(cout<<"| "):(cout<<""); } cout<<endl; } cout<<" -----------------------\n"<<endl; } void printsudotxt() //输出到sudotiku.txt { for(int x=0;x<9;x++) { (x%3==0)?(ocout<<" -----------------------\n "):(ocout<<" "); ocout<<"| "; for(int y=0;y<9;y++) { ocout<<sudo[x][y]<<" "; (y%3==2)?(ocout<<"| "):(ocout<<""); } ocout<<endl; } ocout<<" -----------------------\n"<<endl; } int main() { srand((unsigned)time(NULL)); //这个是种子函数 为rand函数提供不同的种子 每次运行程序产生不同的随机数,不然rand函数每次运行程序产生的随机数都是一样的 ocout.open("sudotiku.txt"); cout<<"请输入数独棋盘题目个数N (0 < N <= 1000000):"<<endl; int N; cin>>N; cout<<"随机生成"<<N<<"个不重复的已解答完毕的数独棋盘如下:"<<endl; ocout << "随机生成"<<N<<"个不重复的已解答完毕的数独棋盘如下:" << endl; for(int i=0;i<N;i++) { clear(sudo); while(!fill(0,1)); printsudo(); printsudotxt(); } ocout.close(); return 0; }
程序运行结果如下:
随机生成3个不重复的已解答完毕的数独棋盘如下:
-----------------------
| 4 1 7 | 3 8 2 | 9 5 6 |
| 2 9 3 | 6 4 5 | 8 7 1 |
| 6 8 5 | 7 9 1 | 2 4 3 |
-----------------------
| 1 7 6 | 5 3 8 | 4 9 2 |
| 8 2 4 | 9 6 7 | 3 1 5 |
| 3 5 9 | 2 1 4 | 6 8 7 |
-----------------------
| 9 3 1 | 4 5 6 | 7 2 8 |
| 5 6 2 | 8 7 9 | 1 3 4 |
| 7 4 8 | 1 2 3 | 5 6 9 |
-----------------------
-----------------------
| 6 7 3 | 1 9 2 | 5 4 8 |
| 2 8 1 | 6 5 4 | 9 7 3 |
| 5 4 9 | 8 7 3 | 2 6 1 |
-----------------------
| 3 9 8 | 4 6 1 | 7 5 2 |
| 4 6 7 | 2 8 5 | 3 1 9 |
| 1 5 2 | 7 3 9 | 4 8 6 |
-----------------------
| 8 2 4 | 3 1 7 | 6 9 5 |
| 7 1 5 | 9 2 6 | 8 3 4 |
| 9 3 6 | 5 4 8 | 1 2 7 |
-----------------------
-----------------------
| 3 4 9 | 6 7 8 | 5 2 1 |
| 7 8 1 | 2 4 5 | 9 3 6 |
| 6 2 5 | 3 1 9 | 8 4 7 |
-----------------------
| 8 5 3 | 4 6 2 | 1 7 9 |
| 2 9 7 | 8 5 1 | 4 6 3 |
| 4 1 6 | 9 3 7 | 2 5 8 |
-----------------------
| 1 3 2 | 7 9 4 | 6 8 5 |
| 5 6 8 | 1 2 3 | 7 9 4 |
| 9 7 4 | 5 8 6 | 3 1 2 |
-----------------------
经测试,程序可以正确运行,运行时间也较短。
通过此次作业,我不仅了解了数独这个游戏,还对回溯的用法有了更深刻的认识,有些平时掌握不牢的知识点,经过程序运行中出现的错误,都能进行很好的纠正。完成这个程序,我花了好几天时间,因为没有思路,所以只能上网查资料,在之后的运行过程中,遇到了如下几个问题:
1.需要在主函数开头加srand((unsigned)time(NULL));这个种子函数,为rand函数提供不同的种子,每次运行程序产生不同的随机数,不然rand函数每次运行程序产生的随机数都是一样的;
2.将程序运行结果输出到sudotiku.txt,ofstream ocout;语句需要写在开头;
3.回溯法的运用,需要理清思路。
这些问题的解决都是通过百度别人的经验来进行解决的。
我认为对我特别重要的技能有以下几项:
1.程序理解(如何理解已有的程序,通过阅读、分析、debug)
2.架构设计、模块化设计、接口设计
3.模块实现、逐步细化
4.效能分析与改进
5.线程之间/进程之间/不同平台的进程之间
6.个人软件过程:估计、记录工作量,并逐步提高
目前我具备的专业知识、技能、能力都处于一个基础阶段,掌握了基本的书面知识和实践技能,希望在学完这门课程后,可以掌握基本的理论和实践知识,通过一般相关企业的面试。