博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
回溯法求解数独算法(C语言)
阅读量:6294 次
发布时间:2019-06-22

本文共 7159 字,大约阅读时间需要 23 分钟。

hot3.png

没有对输入的待解数独进行一般性验证(同一行、一列以及同一个小九宫格都不能出现重复数字)

算法利用回溯的思想:

  1. 从第一个空白处开始,找到其候选解(排除同行、同列以及同一小九宫格的所有出现过的数字,剩下未出现的数字都是候选解)的第一个值填入数独。

  2. 对第二个空白执行第一步(前面所填入的数字对此空白处有影响)。

  3. 当出现某个空白的候选解个数为0时,就开始回溯,找到第一个候选解多于一个的,将其在使用的候选解设为不可取(本程序取值为-1),找到其下一个候选解,继续上面的步骤!

  4. 直到所有空白处填满,运算完成,输出结果!

#include 
#include 
typedef struct node{ int col; int row; int value[10];}Node;int findvalue(int sudoku[9][9], Node * node);int main(void){ int sudoku[9][9] = {
{3, 4, 0, 0, 0, 2, 0, 7, 5},                             {0, 5, 0, 0, 0, 0, 0, 4, 0},                             {0, 0, 0, 8, 0, 0, 2, 0, 0},                             {0, 0, 0, 6, 0, 0, 0, 9, 4},                             {0, 0, 0, 2, 0, 9, 0, 0, 0},                             {4, 9, 0, 0, 0, 8, 0, 0, 0},                             {0, 0, 9, 0, 0, 7, 0, 0, 0},                             {0, 3, 0, 0, 0, 0, 0, 5, 0},                             {2, 7, 0, 9, 0, 0, 0, 1, 3}}; int i, j, k = 0, num_of_empty = 0; int index, temp = 0; //计算所给数独中待填入的空白数 for(i=0; i<9; i++) for(j=0; j<9; j++) if(sudoku[i][j]==0) num_of_empty++; //为回溯栈分配空间 Node * node_stack = (Node *)malloc(sizeof(struct node) * num_of_empty); //回溯法求解数独 while(num_of_empty) { for(i=0; i<9; i++) for(j=0; j<9; j++) if(sudoku[i][j]==0) { //初始化栈中存储候选值的数组 for(index=0; index<10; index++) (node_stack + k)->value[index] = 0; (node_stack + k)->col = i; (node_stack + k)->row = j; sudoku[i][j] = findvalue(sudoku, node_stack + k); if(sudoku[i][j]==-1) { sudoku[i][j] = 0; k--; while((node_stack + k)->value[0]==1) { sudoku[(node_stack + k)->col][(node_stack + k)->row] = 0; num_of_empty++; k--; } (node_stack + k)->value[0]--; i = (node_stack + k)->col; j = (node_stack + k)->row; for(index=1; index<10; index++) if((node_stack + k)->value[index]==0) { (node_stack + k)->value[index] = -1; break; } for(index=1; index<10; index++) if((node_stack + k)->value[index]==0) { sudoku[i][j] = index; break; } } k++; } //当栈空,说明数独错误,无解 if(k==0) { printf("此数独无解!\n"); free(node_stack); return 0; } num_of_empty--; } free(node_stack); //打印数独 for(i=0; i<9; i++) { for(j=0; j<9; j++) printf("%2d ", sudoku[i][j]); printf("\n"); } return 0;}int findvalue(int sudoku[9][9], Node * node){ int m, n, i = node->col, j = node->row; for(m=1; m<10; m++) { if(node->value[sudoku[i][m-1]]==0) node->value[sudoku[i][m-1]] = sudoku[i][m-1]; if(node->value[sudoku[m-1][j]]==0) node->value[sudoku[m-1][j]] = sudoku[m-1][j]; } for(m=0; m<3; m++) for(n=0; n<3; n++) if(node->value[sudoku[i/3*3+m][j/3*3+n]]==0) node->value[sudoku[i/3*3+m][j/3*3+n]] = sudoku[i/3*3+m][j/3*3+n]; for(m=1; m<10; m++) if(node->value[m]==0) node->value[0]++; for(m=1; m<10; m++) if(node->value[m]==0) break; if(node->value[0]==0) return -1; else return m; }

做了下改进:将各个步骤独立成函数,加入了待解数独的前期一般性检查,还有部分代码优化

#include 
#include 
#define BOOL int#define FALSE 1#define TRUE 0typedef struct node{ int col; int row; int value[10];} Node;int findvalue(int sudoku[9][9], Node * node);BOOL general_inspection(int sudoku[9][9]);int blank_num(int sudoku[9][9]);Node * mem_alloc(int num_of_empty);void trace(int sudoku[9][9], Node * node_stack, int num_of_empty);void print_sudoku(int sudoku[9][9]);int main(void){ int sudoku[9][9] = {
{3, 4, 1, 0, 0, 2, 0, 7, 5}, {0, 5, 0, 0, 0, 0, 0, 4, 0}, {0, 0, 0, 8, 0, 0, 2, 0, 0}, {0, 0, 0, 6, 0, 0, 0, 9, 4}, {0, 0, 0, 2, 0, 9, 0, 0, 0}, {4, 9, 0, 0, 0, 8, 0, 0, 0}, {0, 0, 9, 0, 0, 7, 0, 0, 0}, {0, 3, 0, 0, 0, 0, 0, 5, 0}, {2, 7, 0, 9, 0, 0, 0, 1, 3}}; int num_of_empty; //为回溯栈分配空间 Node * node_stack; if(general_inspection(sudoku)) { printf("此数独存在错误!请检查\n"); print_sudoku(sudoku); return 0; } num_of_empty = blank_num(sudoku); node_stack = mem_alloc(num_of_empty); trace(sudoku, node_stack, num_of_empty); print_sudoku(sudoku); return 0;}BOOL general_inspection(int sudoku[9][9]){ int temp[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int i, j, m, n; for(i=0; i<9; i++) for(j=0; j<9; j++) if(sudoku[i][j]!=0) { //检查所在行 for(m=0; m<10; m++) temp[m] = 0; for(m=0; m<9; m++) if(sudoku[i][m]!=0) { if(temp[sudoku[i][m]]==0) temp[sudoku[i][m]] = 1; else return FALSE; } //检查所在列 for(m=0; m<10; m++) temp[m] = 0; for(m=0; m<9; m++) if(sudoku[m][j]!=0) { if(temp[sudoku[m][j]]==0) temp[sudoku[m][j]] = 1; else return FALSE; } //检查所在九宫格 for(m=0; m<10; m++) temp[m] = 0; for(m=0; m<3; m++) for(n=0; n<3; n++) if(sudoku[i/3*3+m][j/3*3+n]!=0) { if(temp[sudoku[i/3*3+m][j/3*3+n]]==0) temp[sudoku[i/3*3+m][j/3*3+n]] = 1; else return FALSE; } } return TRUE;}int blank_num(int sudoku[9][9]){ //计算所给数独中待填入的空白数 int i, j, num = 0; for(i=0; i<9; i++) for(j=0; j<9; j++) if(sudoku[i][j]==0) num++; return num;}Node * mem_alloc(int num_of_empty){ Node * node_stack = (Node *)malloc(sizeof(struct node) * num_of_empty); if(node_stack==NULL) { printf("内存分配失败!\n"); exit(1); } return node_stack;}void trace(int sudoku[9][9], Node * node_stack, int num_of_empty){ int i, j, index, k = 0; //回溯法求解数独 while(num_of_empty) { for(i=0; i<9; i++) { for(j=0; j<9; j++) { if(sudoku[i][j]==0) { (node_stack + k)->col = i; (node_stack + k)->row = j; sudoku[i][j] = findvalue(sudoku, node_stack+k); if(sudoku[i][j]==-1) { sudoku[i][j] = 0; k--; while((node_stack + k)->value[0]==0) { //当栈空,说明数独错误,无解 if(k==0) { printf("此数独无解!\n"); //free(node_stack); //为啥这里一释放内存,就弹出debug assertion failed窗口啊! exit(1); } sudoku[(node_stack + k)->col][(node_stack + k)->row] = 0; num_of_empty++; k--; } for(index=1; index<10; index++) if((node_stack + k)->value[index]==0) { sudoku[(node_stack + k)->col][(node_stack + k)->row] = index; (node_stack + k)->value[index] = 1; (node_stack + k)->value[0]--; break; } num_of_empty++; i = (node_stack + k)->col; j = (node_stack + k)->row; } k++; num_of_empty--; } } } } //栈空间使用结束,释放 free(node_stack); node_stack=NULL;}int findvalue(int sudoku[9][9], Node * node){ int m, n, i = node->col, j = node->row; //初始化栈中存储候选值的数组 for(m=0; m<10; m++) node->value[m] = 0; for(m=1; m<10; m++) { node->value[sudoku[i][m-1]] = 1; node->value[sudoku[m-1][j]] = 1; } for(m=0; m<3; m++) for(n=0; n<3; n++) node->value[sudoku[i/3*3+m][j/3*3+n]] = 1; //node->value[0]记录候选值个数,前面的循环可能会修改掉它,需要重新赋0值 node->value[0] = 0; for(m=1; m<10; m++) if(node->value[m]==0) node->value[0]++; for(m=1; m<10; m++) if(node->value[m]==0) { node->value[m] = 1; node->value[0]--; break; } //返回候选值m,若无候选值可用,返回错误标记-1 if(m==10) return -1; else return m;}void print_sudoku(int sudoku[9][9]){ //打印数独 int i, j; for(i=0; i<9; i++) { for(j=0; j<9; j++) printf("%2d ", sudoku[i][j]); printf("\n"); }}

转载于:https://my.oschina.net/lovewxm/blog/288043

你可能感兴趣的文章
科创板7天受理28家公司,但后者“含金量”备受质疑
查看>>
交通运输部部长李小鹏谈及自动驾驶:包容失败、反对垄断,力争在国家层面出台指导意见...
查看>>
退市35年后,牛仔裤品牌李维斯要重新IPO了
查看>>
PHP 7.3声称速度比PHP 5快3倍还多,值得更新了!
查看>>
elasticsearch使用指南之Elasticsearch Document Index API详解、原理与示例
查看>>
操作符分类
查看>>
VCTransitionsLibrary –自定义iOS交互式转场动画的库
查看>>
11家车企联手高通、大唐,加速V2X在华商用部署
查看>>
WPF Viewport3D 解决透视模式时窗体模糊
查看>>
PowerDesigner反向生成物理数据模型
查看>>
杰思安全获数千万元A+轮投资,绿盟科技领投,德联资本跟投
查看>>
Google 的最后努力 :请求最高法院撤回 88 亿罚单
查看>>
服气!3小时竟能写出风靡全球的小游戏,还顺手就赚的盆满钵满
查看>>
第七篇:SpringBoot 2.x集成Lombok
查看>>
【对讲机的那点事】带你玩转灵通LT33公网集群对讲机
查看>>
Kettle性能调优汇总
查看>>
浅谈网络爬虫中广度优先算法和代码实现
查看>>
第十九章:集合视图(二十一)
查看>>
分享一个算法,计算能在任何背景色上清晰显示的前景色
查看>>
javaScript系列 [01]-javaScript函数基础
查看>>