数独算法

xiaoxiao2021-02-27  192

程序 = 数据结构+算法

说明:

1.   在计算机内部使用0..8表示1..9。在pc和用户之间的接口使用1..9,这里的人机接口是显示和矩阵初始化配置。

2. 需要一个配置文件,用来配置数独的原始数据,大致内容如下

// memo 

// format x,y,v 

// line begining with '/' or ' ' will be ignored 

1,4,3 

1,9,4

数据结构

1. int16_t maze[x][y]  用来表示数独的状态。 

     a. 如果maze[x][y]<0,那么maze[x][y]上有确定的值为-maze[x][y]。比如,如果maze[0][0]=-7,意思是maze[0][0]是确定的数字为7。

     b.如果maze[x][y]>0,表示该x,y位置上可以使用那些可能的数字。比如,如果maze[0][0]=7=B000000111,表示位置[0][0]只可能放0, 1, 2,其他的数字绝对不可能;

2. uint16_t mask[SCALE+1]   用来保存位数的bit表示,比如针对0,mask[0]=000000001。使用mask主要做位运算,计算某个位置上可以放置那些数字

3. int16_t*maze_p[SCALE*3][SCALE]   maze_p是对maze的不同视角的解释,包括:以行的角度解释maze,以列的角度解释maze,和以cell(一个宫格)解释的maze。具体作用后面分析算法做解释。

 

算法:

数独的算法其实很简单,不需要复杂的什么深度搜索,核心思想就是:针对某些element,找到唯一解,然后再多次迭代,依次找到其他的值。如何找唯一解是关键。我们知道,数独的约束条件是:每行、每列和每个cell(宫)都是0..8,不能重复。因此,找唯一解的方法是:统计0..8各个数字出现的可能性,如果可能性只能是1,就是唯一解。

以下面红色maze[0][0]为例:

1.  首先看第一行,maze[0][0]只可能是数字12478,用二进制表示就是 110010110

2.  再看第一列,maze[0][0]只可能是数字023456,用二进制表示就是001111101。和第一个条件与,110010110 && 001111101 = 000010100。这里得出的结论就是,maze[0][0]只能是2和4.

3.  再看第一个cell(宫格), maze[0][0]只可能是数字125678,用二进制表示就是111100110。和前面的结果与,111100110 && 000010100= 000000100。这里得出的结论就是,maze[0][0]只能是2.

 

0

 

 

5

3

 

 

6

 

 

 

 

 

 

 

 

 

 

3

4

 

 

 

 

 

 

8

 

 

 

 

 

 

 

 

7

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

算法的思想是:依次计算每行,每列,和每个宫,计算每个element里面可以存放数字的可能性。如果某个数字的可能性是1,就说明找到了这个element的唯一解。

就这样,多次迭代后,很快就可以算出所有的解。

 

下面是使用后面的源程序的结果。第一个矩阵是原始数据,'-'表示未确定之数。下面的这个例子经过9次迭代,就算出了结果。

- - - 3 - - - 8 4 - 4 2 5 8 - - - - - - 5 4 - 7 - 9 - 7 8 - 1 - - - 6 - - 6 1 8 5 - - - - - - 3 - 7 - 8 - - - 9 - 7 - - 6 - 8 - 2 - - 4 8 - - - - - 8 - 9 - 4 - 3 - - - 3 - - 5 8 4 - 4 2 5 8 - - - - 8 3 5 4 - 7 - 9 - 7 8 - 1 - - - 6 - - 6 1 8 5 - - - - - - 3 9 7 6 8 - - - 9 - 7 - - 6 - 8 3 2 - - 4 8 - - - - - 8 - 9 - 4 - 3 - - - 3 - - 5 8 4 - 4 2 5 8 - - - - 8 3 5 4 - 7 - 9 - 7 8 - 1 - - - 6 5 - 6 1 8 5 - - - - - - 3 9 7 6 8 - - - 9 - 7 - - 6 - 8 3 2 - 6 4 8 - - - - - 8 2 9 - 4 - 3 - 7 6 3 - - 5 8 4 - 4 2 5 8 - - - - 8 3 5 4 - 7 - 9 - 7 8 - 1 - - - 6 5 - 6 1 8 5 - - - - - - 3 9 7 6 8 - - - 9 - 7 - - 6 2 8 3 2 - 6 4 8 - 5 - 6 - 8 2 9 - 4 - 3 - 7 6 3 - - 5 8 4 - 4 2 5 8 - - - 6 8 3 5 4 6 7 - 9 - 7 8 9 1 - - - 6 5 - 6 1 8 5 - - - - - - 3 9 7 6 8 - - 5 9 - 7 - - 6 2 8 3 2 7 6 4 8 - 5 - 6 1 8 2 9 - 4 - 3 - 7 6 3 - - 5 8 4 - 4 2 5 8 - 7 - 6 8 3 5 4 6 7 - 9 - 7 8 9 1 - 4 - 6 5 - 6 1 8 5 - 9 - 7 - 5 3 9 7 6 8 - - 5 9 4 7 - - 6 2 8 3 2 7 6 4 8 - 5 - 6 1 8 2 9 5 4 7 3 - 7 6 3 - - 5 8 4 - 4 2 5 8 - 7 3 6 8 3 5 4 6 7 - 9 - 7 8 9 1 - 4 3 6 5 - 6 1 8 5 - 9 4 7 - 5 3 9 7 6 8 1 2 5 9 4 7 - - 6 2 8 3 2 7 6 4 8 1 5 9 6 1 8 2 9 5 4 7 3 - 7 6 3 - 2 5 8 4 - 4 2 5 8 9 7 3 6 8 3 5 4 6 7 2 9 1 7 8 9 1 2 4 3 6 5 2 6 1 8 5 3 9 4 7 4 5 3 9 7 6 8 1 2 5 9 4 7 3 1 6 2 8 3 2 7 6 4 8 1 5 9 6 1 8 2 9 5 4 7 3 9 7 6 3 1 2 5 8 4 1 4 2 5 8 9 7 3 6 8 3 5 4 6 7 2 9 1 7 8 9 1 2 4 3 6 5 2 6 1 8 5 3 9 4 7 4 5 3 9 7 6 8 1 2 5 9 4 7 3 1 6 2 8 3 2 7 6 4 8 1 5 9 6 1 8 2 9 5 4 7 3

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include "main.h" int16_t maze[SCALE][SCALE]; uint16_t mask[SCALE+1]; int16_t* maze_p[SCALE*3][SCALE]; char s_buf[1024]; void preConfig() { char *file = "config.txt"; FILE* fh = fopen(file, "r"); char *token; if(!fh) { printf("cannot open %s\n", file); return; } while(fgets(s_buf, 1024, fh)){ int counter = 0; int x=0,y=0,v=0; if(('/' == s_buf[0]) || (' ' == s_buf[0]) || ('\n' == s_buf[0])) continue; token = strtok( s_buf, ","); while(token !=NULL) { if(0 == counter) x = atoi(token); else if(1 == counter) y = atoi(token); else if(2 == counter){ v = atoi(token); break; } counter++; token=strtok(NULL, ","); } //check validation if((x>SCALE) || (y>SCALE) ||(v>SCALE)) { printf("%d %d %d each should be less than %d", x,y,v, SCALE); continue; } else ; //printf("%d %d %d %d\n", x,y,v, counter); if(counter>0) maze[x-1][y-1] = -(v-1); } } void init() { int i,j,m,n; int counter; int x,y; j=1; mask[0]=1; for(i=1;i<SCALE;i++){ j *=2; mask[i]=j; } mask[SCALE] = (2<<(SCALE-1))-1; for(i=0;i<SCALE;i++) for(j=0;j<SCALE;j++) maze[i][j] = mask[SCALE]; counter=0; for(i=0;i<SCALE;i++) { for(j=0;j<SCALE;j++) maze_p[counter][j] = &maze[i][j]; counter++; } for(i=0;i<SCALE;i++) { for(j=0;j<SCALE;j++) maze_p[counter][j] = &maze[j][i]; counter++; } for(i=0;i<CELL_SIZE;i++) for(j=0;j<CELL_SIZE;j++) { for(m=0;m<CELL_SIZE;m++) for(n=0;n<CELL_SIZE;n++) { int t = m*CELL_SIZE+n; x = i*CELL_SIZE + m; y = j*CELL_SIZE + n; maze_p[counter][t] = &maze[x][y]; } counter++; } preConfig(); } char* printB(uint16_t v){ static char string[10]; int i; for(i=0;i<SCALE;i++) string[i] = '0'; i=SCALE; while(i-->0) { string[i] = v%2?'1':'0'; v=v/2; } return string; } void printMaze() { int i,j; for(i=0;i<SCALE;i++) { for(j=0;j<SCALE;j++) { printf("%c ", maze[i][j]>0?'-':(-maze[i][j]+'1')); } printf("\n"); } printf("\n"); } bool isSolved() { int i,j; for(i=0;i<SCALE;i++) for(j=0;j<SCALE;j++) if(maze[i][j]>0) return false; return true; } void statistics(uint8_t* number_static, int16_t value, uint8_t* array, int num) { int i=0; while(i<SCALE) { if(value %2){ number_static[i]++; array[i] = num; //use array to remember the location of the number i } i++; value = value / 2; } } void process() { int i,j; int result; int16_t* element; uint8_t stat[SCALE]; uint8_t loc_marker[SCALE]; for(i=0;i<3*SCALE;i++) { //get the mask for the 9 elements result=0; for(j=0;j<SCALE;j++) { element = maze_p[i][j]; if(*element<=0) result |= mask[-*element]; } //apply the mask to each >0 element for(j=0;j<SCALE;j++) { element = maze_p[i][j]; if(*element>0) *element &= ~result; } //statistics for(j=0;j<SCALE;j++) { stat[j]=0x0; loc_marker[j]=0; } for(j=0;j<SCALE;j++) { element = maze_p[i][j]; if(*element>0) {//to statistics statistics(stat, *element, loc_marker, j); } else { stat[-*element]=0; //means number of j has been decided } } //check statistics results for(j=0;j<SCALE;j++) { if(1 == stat[j]) {//find answer for number of j *maze_p[i][loc_marker[j]] = -j; } } } } int main() { int counter=0; init(); //printMaze(); do{ process(); printMaze(); counter++; }while(!isSolved()); printf("Counter=%d\n",counter); return 1; }

转载请注明原文地址: https://www.6miu.com/read-12596.html

最新回复(0)