数独 九宫格 破解
說到數(shù)獨,或者九宮格,我想大家一定都不陌生,初中高中看的各種雜志上都有這種益智游戲,現(xiàn)在的智能手機上也有人寫出了這種游戲,閑暇時候玩玩也能活躍一下腦子。還有看《模仿游戲》這部電影里面,圖靈在選拔隊友的時候好像出的也是數(shù)獨的題目。
我本來對數(shù)獨不是太感興趣,但是一個偶然的機會看到朋友在玩這個游戲,就想寫出一個破解算法,來在朋友面前炫耀一下,也可以順便復(fù)習(xí)一下最近學(xué)習(xí)的C語言。
數(shù)獨事實上就是一個9*9的一個方陣,之所以又叫九宮格,是因為其中每3*3的方陣為一宮,整個大方陣有九個這樣的宮。規(guī)則是在每一行每一列填上1~9九個數(shù)字,使得各行各列填滿且不重復(fù),并且每一宮中的數(shù)字也是1~9不重復(fù)。
對于算法來講,主要使用遞歸,對于數(shù)據(jù)結(jié)構(gòu)來講,用二維數(shù)組來表示9*9的方陣,然而每一個位置都有兩個屬性,即數(shù)值和所在的宮,所以一開始我先聲明了一個結(jié)構(gòu)體來包含這兩個屬性。然后用一個分配算法來分配各個位置的數(shù)字所在的宮。具體的破解算法其實就是讓程序去測試每一個位置該填什么數(shù)字,需要判斷每一行,每一列,每一宮是否有重復(fù),都沒有重復(fù)則表示成功。如果成功則保留,不成功則退回重新測試。通過輸入原始數(shù)據(jù)來讓程序運行,程序執(zhí)行后如果有解則輸出方陣,如果沒有則輸出無解。具體程序如下(C語言):
#include<stdio.h> #include<stdlib.h> #define _CRT_SECURE_NO_DEPRECATE #pragma warning(disable:4996) #define N 9struct theNums{int num;//數(shù)字int pala;//所在的宮 }; struct theNums tn[N][N];int result = 0; //結(jié)果數(shù)void sharePal(struct theNums shnum[N][N]){//分配宮格int row, col;for (row = 1; row <= N; row++){for (col = 1; col <= N; col++){if (row >= 1 && row <= 3){if(col >= 1 && col <= 3)shnum[row - 1][col - 1].pala = 1;else if (col >= 4&& col <= 6)shnum[row - 1][col - 1].pala = 2;elseshnum[row - 1][col - 1].pala = 3;}else if (row >= 4 && row <= 6){if (col >= 1 && col <= 3)shnum[row - 1][col - 1].pala = 4;else if (col >= 4 && col <= 6)shnum[row - 1][col - 1].pala = 5;elseshnum[row - 1][col - 1].pala = 6;}else{if (col >= 1 && col <= 3)shnum[row - 1][col - 1].pala = 7;else if (col >= 4 && col <= 6)shnum[row - 1][col - 1].pala = 8;elseshnum[row - 1][col - 1].pala = 9;}}} }bool check(struct theNums chenum[N][N], int row, int col, int key){int i, j;//判斷行for (i = 0; i < N; i++){if (chenum[row][i].num == key)return false;}//判斷列for (j = 0; j<N; j++){if (chenum[j][col].num == key)return false;}//判斷所在的宮for (i = 0; i < N; i++){for (j = 0; j < N; j++){if (chenum[i][j].pala == chenum[row][col].pala){if (chenum[i][j].num == key)return false;}}}//可行return true; }int printNum(struct theNums num[N][N]){//輸出九宮格result++;printf("第%d個填法為:\n", result);int i, j;for (i = 0; i < N; i++){for (j = 0; j < N; j++){printf("%3d", num[i][j].num);if (j == 2 || j == 5)printf("\t");}printf("\n");if (i == 2 || i == 5)printf("\n");}return 0; }void CrossWords(struct theNums CWnum[N][N], int n) {//九宮格破解算法struct theNums temp[N][N];int i, j;for (i = 0; i<9; i++){for (j = 0; j < 9; j++){temp[i][j].num = CWnum[i][j].num;temp[i][j].pala = CWnum[i][j].pala;}}i = n / 9; j = n % 9; //求出第n個數(shù)的行數(shù)和列數(shù)if (CWnum[i][j].num != 0) //已經(jīng)有原始數(shù)據(jù){if (n == 80) //是最后一個格子,輸出可行解printNum(temp);else //不是最后一個格子,求下一個格子CrossWords(temp, n + 1);}else //沒有數(shù)據(jù){for (int k = 1; k <= 9; k++){bool flag = check(temp, i, j, k);if (flag) //第i行、第j列可以是k{temp[i][j].num = k; //設(shè)為kif (n == 80)printNum(temp);elseCrossWords(temp, n + 1);temp[i][j].num = 0; //恢復(fù)為0,判斷下一個k}}} }void main(){printf("請輸入數(shù)獨中的原始數(shù)據(jù),沒有數(shù)據(jù)的用0代替。\n");for (int i = 0; i<N; i++){printf("Please Input第%d行Numbers:", i + 1);for (int j = 0; j<N; j++)scanf("%d", &tn[i][j].num);}sharePal(tn);printf("數(shù)獨的解為:\n\n");CrossWords(tn, 0);if (result == 0)printf("Bad Input,無解!"); // printNum(tn);//輸出九宮格system("pause"); }舉個例子,芬蘭數(shù)學(xué)家因卡拉花費3個月設(shè)計出了世界上迄今難度最大的九宮格游戲,而且它只有一個答案(皮埃斯:人家花3個月才搞出來的程序一跑幾秒就跑出來了,是對先人的不敬還是時代發(fā)展的必然),如下圖:
總結(jié)
- 上一篇: ArrayDeque(双端队列的线性实现
- 下一篇: 灵敏度(sensitivity)和特异性