用C语言做数独
前言:數獨,相信大家都不陌生,它是源自18世紀瑞士的一種數學游戲。是一種運用紙、筆進行演算的邏輯游戲。玩家需要根據9×9盤面上的已知數字,推理出所有剩余空格的數字,并滿足每一行、每一列、每一個粗線宮(3*3)內的數字均含1-9,不重復。數獨盤面是個九宮,每一宮又分為九個小格。在這八十一格中給出一定的已知數字和解題條件,利用邏輯和推理,在其他的空格上填入1-9的數字。使1-9每個數字在每一行、每一列和每一宮中都只出現一次。這種取材簡單,容易上手的益智小游戲,其熱度絲毫不亞于掃雷(今后我還會帶來用C語言征服掃雷,感興趣就多多關注!!)。今天,我們就有學過的C語言知識去征服它。
問題分析:下圖就是一個普通的未完成的數獨,是個9 x 9的各自圖,其中分為9大塊,從左往右,從上到下,稱第1,2,3,...宮格。如果用坐標來表示每個格子,比如第一行第三個數字6的坐標就為(0,2),第二行第三列沒有數字的坐標為(1,2)。那么按照數獨的規則,對于坐標(1,2)空格有用的信息就只有與之相同的整一行,整一列以及其所在的宮格,為第二行,第三列以及第一宮格。這些地方出現的數字有(1,2,3,4,6,7),那么這個格子就只能填(5,8,9)其中的一個數字,顯然這個格子是信息不足的。那作為一個正常的數獨題,一定是會存在那個信息量充足的空格子。比如這題中的坐標為(3,8),與之同一行,同一列以及同一宮格出現的數字有(1,2,3,4,5,7,8,9),所以這個空格就只能填6。
?有了以上分析,首先我們就要獲得對于一個坐標格子有用的信息。在此之前呢我們定義一個儲存初始數獨信息的二維數組,并輸入相關信息。代碼如下。
main() {int NumAlone[9][9]; //儲存數獨int i,j;for(i=0;i<9;i++){for(j=0;j<9;j++){scanf("%d",&NumAlone[i][j]); //數組賦值}} }接著,我們先獲取同一行列的數字信息,并用數組mArray儲存起來,其儲存的方式是,下標加一對應數字,其值為0,說明未出現該數字,值為1,說明出現了該數字。比如mArray[2]=1,表示數字3出現過,該坐標下的空格也就不能填3。代碼如下。
main() {int NumAlone[9][9],mArray[9]; //儲存數獨和儲存信息數組int i,j,m,k;for(i=0;i<9;i++){for(j=0;j<9;j++){scanf("%d",&NumAlone[i][j]); //數組賦值}mArray[i]=0; //初始化}line(NumAlone,mArray,1); //獲取同一行數字信息,參數為數獨數組,信息數組,橫坐標row(NumAlone,mArray,3); //同上,獲取同一列數字信息 }void line(int array[][9],int *p,int n) {for(int i=0;i<9;i++){p[array[n][i]-1] = 1; //信息數組賦值,下同} }void row(int array[][9],int *p,int n) {for(int i=0;i<9;i++){p[array[i][n]-1] = 1;} }獲取行列信息之后,接下來就是獲取同一宮格的數字信息,比獲取行列數字信息麻煩點。先要明白該坐標處于第幾宮格。首先很明顯的一點,九個宮格的中心坐標都很清楚,分別為(1,1)(1,4)(1,7)(4,1)(4,4)(4,7)(7,1)(7,4)(7,7)。那么只需要判斷該坐標與幾個中心坐標的距離是否小于根號二,即可獲得其所在九宮格的中心坐標。比如坐標(3,8)和中心坐標(4,7)的距離就剛好等于根號二,故其所在宮格的中心坐標就為(4,7)。那么再來個雙重循環,就可以得到該九宮格的數字信息。代碼如下
int SudokuPosition(int x,int y) //判斷九宮格中心坐標位置,參數為空格坐標 {int i,j,a,b,result;for(i=1;i<=7;i+=3){for(j=1;j<=7;j+=3){a=abs(x-i);b=abs(y-j);if(pow(a,2) + pow(b,2) <= 2){ //判斷距離result=i*10+j;break;}}}return result; }void SquireNine(int array[][9],int *p,int x,int y) //獲取九宮格數字信息 {int i,j,xy,a,b;xy=SudokuPosition(x,y); //中心坐標信息a=xy/10-1;b=xy%10-1; //信息解析for(i=a;i<a+3;i++){for(j=b;j<b+3;j++){p[array[i][j]-1] = 1; //信息數組賦值}} }以上就把所有該獲取的數字信息全部獲取完畢。接下來就是處理信息,即處理信息數組mArray,判斷其含0的個數,如果只有1個,說明信息充足,返回值為0的下標加一,這就是填入該空格子的數字。代碼如下
int judgeNum(int *p) //處理信息數組,參數為信息數組 {int flag=0,k;for(int i=0;i<9;i++){if(p[i]==0){ //判斷值為0的個數,并記錄其下標flag++;k=i+1;}}if(flag==1){ //據情況返回值return k;}else{return 0;} }到這里我們就能給空格子填空了,但是做數獨是一個循序漸進的過程,所以我們要不斷循環獲取某個格子的數字信息,判斷其信息是否充足,如果充足,則填入相應的數字,反反復復,每一步都需要用到已經填過的數字。但是程序不能一直跑下去,所以需要一個判斷數獨是否填完的函數。很簡單,代碼如下
int Prepare(int Array[][9]} //判斷數獨是否填完,參數為數獨數組 {int i,j,flag=0;for(i=0;i<9;i++){for(j=0;j<9;j++){if(Array[i][j]==0){flag=1; //如果還有為0的格子,則未填完}}}return flag; }到這里就解決了所有問題,下面放出完整代碼,給出相應的輸入輸出。
#include<stdio.h> #include<math.h> void line(int array[][9],int *p,int n); void row(int array[][9],int *p,int n); int judgeNum(int *p); int SudokuPosition(int x,int y); void SquireNine(int array[][9],int *p,int x,int y); void FillBlank(int array[][9],int *p,int x,int y); int Prepare(int Array[][9]);main() {int NumAlone[9][9],mArray[9];int i,j,m,k;for(i=0;i<9;i++){for(j=0;j<9;j++){scanf("%d",&NumAlone[i][j]);}mArray[i]=0;}//line(NumAlone,mArray,1);//row(NumAlone,mArray,3);//SquireNine(NumAlone,mArray,1,3);//FillBlank(NumAlone,mArray,1,3);while(Prepare(NumAlone)){for(i=0;i<9;i++){for(j=0;j<9;j++){if(NumAlone[i][j]==0){for(m=0;m<9;m++){mArray[m]=0;}line(NumAlone,mArray,i);row(NumAlone,mArray,j);SquireNine(NumAlone,mArray,i,j);FillBlank(NumAlone,mArray,i,j);}}}}printf("\n\n");for(m=0;m<9;m++){for(k=0;k<9;k++){printf("%d ",NumAlone[m][k]);}printf("\n");}return 0; }void line(int array[][9],int *p,int n) {for(int i=0;i<9;i++){p[array[n][i]-1] = 1;} }void row(int array[][9],int *p,int n) {for(int i=0;i<9;i++){p[array[i][n]-1] = 1;} }void SquireNine(int array[][9],int *p,int x,int y) {int i,j,xy,a,b;xy=SudokuPosition(x,y);a=xy/10-1;b=xy%10-1;for(i=a;i<a+3;i++){for(j=b;j<b+3;j++){p[array[i][j]-1] = 1;}} }int judgeNum(int *p) {int flag=0,k;for(int i=0;i<9;i++){if(p[i]==0){flag++;k=i+1;}}if(flag==1){return k;}else{return 0;} }int SudokuPosition(int x,int y) {int i,j,a,b,result;for(i=1;i<=7;i+=3){for(j=1;j<=7;j+=3){a=abs(x-i);b=abs(y-j);if(pow(a,2) + pow(b,2) <= 2){result=i*10+j;break;}}}return result; }void FillBlank(int array[][9],int *p,int x,int y) {array[x][y]=judgeNum(p); }int Prepare(int Array[][9]) {int i,j,flag=0;for(i=0;i<9;i++){for(j=0;j<9;j++){if(Array[i][j]==0){flag=1;}}}return flag; }?
?
?以上就是我要分享的全部內容了,覺得還不錯的話,可以多點贊喲!
總結
- 上一篇: 非监督学习的单层网络分析
- 下一篇: 服务器专用影子系统,试试最牛X的影子系统