[ C语言版 ] 数独计算器 [ 搜索剪枝法 ]
【原创】转载请注明出处。 【浙江大学 程序设计专题】
使用方法:按提示输入方式为9*9的矩阵,0表示未知数。
为解决这一问题,我们也尝试了两种方法,准确的说,是第一种方法太慢了,我们对它进行了优化。
方法一:
用最朴素的方法逐一枚举每一个格子,在某一个格子不能填入任何数字时回溯。
这个方法写法相对简单,但对于一些难以求解的情况,程序会非常慢,最慢的甚至无法在3秒内得出答案。如果每一个情况需要三秒钟来求解,那么要批量求解数独可能需要等好几分钟。
尽管我们将编译器的优化选项开到最高,一些情况仍需要1秒左右。
方法二:
模拟手算,当给定一道题目时,首先确定每个格子可以填那些数字,每次优先选择可选数字最少的格子。
此方法对于大多数数据能在0.1秒内求解。
方法一样例解释:绿色数字表示有多重可能的格子,红色数字表示唯一可能的格子,红色填充的格子表示无法填入数字。

方法二样例:


方法一代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "prnt_sudoku.h" /*Sudoku save in array Map, index counts from 0.*/
int Map[][],cnt;
/*R<->Row B<->Block C<->Column*/
int R[][],B[][],C[][];
/*characters on the left and right of output-numbers.*/
/*this will make user know which numbers are given at first.*/
char C1[][],C2[][]; int Dfs(const int x,const int y)
{
if(x==)
{
printf("\n\n\tSolution #%d: \n\n",++cnt);
Print(Map,C1,C2);
/*when there are too many solutions return 1*/
/*and the whole Search algorithm will stop*/
if(cnt==) return ;
return ;
} if(Map[x][y]) { return Dfs(x+(y+)/,(y+)%); }
/*if (x,y) is known, then fill the next one.*/ int i;
for(i=;i<=;++i)
{
/*Check if setting i in blank(x,y) is proper.*/
if(R[x][i] || C[y][i] || B[x/*+y/][i])continue; /*update arrays*/
Map[x][y]=i;
R[x][i]=; C[y][i]=; B[x/*+y/][i]=; if(Dfs(x+(y+)/,(y+)%)) return ;
/*this expression will fill blanks from the left-up one to */
/* the right-down one automaticly.*/ /*undo*/
R[x][i]=; C[y][i]=; B[x/*+y/][i]=;
Map[x][y]=;
}
return ;
} int main()
{
int op,T=;
system("cls");
printf("Choose input/output way(1.Keyboard/2.File): ");
while()/*until receiving an expected input.*/
{
scanf("%d",&op);
if(op==)break;
if(op==)/*file input*/
{
char File_Name[];
printf("Please input File_Name: ");
scanf("%s",File_Name);
printf("\n\tResult Will Save to Result.txt\n\n");
printf("\tCalculating....\n\n");
freopen(File_Name,"r",stdin);
freopen("Result.txt","w",stdout);/*answer file is "Result.txt" */
break;
}
} while()/*Support multi-set test, read to EOF.*/
{
/*Initialize*/
memset(R,,sizeof(R));
memset(C,,sizeof(C));
memset(B,,sizeof(B));
memset(Map,,sizeof(Map));
cnt=;
if(op==)printf("Please Input 9*9 matrix(0 for space):\n");
int i,j,data;
/*Read until EOF*/
for(i=;i<;++i) for(j=;j<;++j)
{
if(!(~scanf("%1d",&data)))
{
if(op==)system("pause");
fclose(stdin);
return ;
}
Map[i][j]=data;
R[i][data]++;
C[j][data]++;
B[i/*+j/][data]++;
} printf("Test Case #%d: ",++T);
int f=;/*Check if the sudoku is valid.*/
for(i=;i<;++i) for(j=;j<=;++j)
if(R[i][j]>|| C[i][j]> || B[i][j]>) f=;
if(f)/*Invalid input*/
{
fprintf(stderr,"\n\t\tError in Test Case #%d: ",T);
fprintf(stderr,"Invalid Input.\n");
printf("\n\n\tFiled: No Solution Found!\n\n");
continue;
} /*Mark the known grids.*/
for(i=;i<;++i) for(j=;j<;++j)
if(Map[i][j])C1[i][j]='[',C2[i][j]=']';
else C1[i][j]=C2[i][j]=' '; int t1=clock();/*Timer*/
if(Dfs(,))
/*In case of costing too much time and disk storage,*/
/*Dfs(int,int) will find at most 5000 kinds of solution.*/
{
fprintf(stderr,"\n\t\tError in Test Case #%d: ",T);
fprintf(stderr,"Too much solution! Calculation has broken.\n");
} /*output the time*/
if(cnt==) printf("\n\n\tFiled: No Solution Found!\n\n");
else printf("\n\n\t%d Solution Found In %ldms.\n\n",cnt,*(clock()-t1)/CLOCKS_PER_SEC);
} return ;
}
方法二代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "prnt_sudoku.h" struct PII { int x,y; }; /*Sudoku save in array Map, index counts from 0.*/
int Map[][],cnt;
/*F[i][j][k] refers to that, in grid (i,j), number k is used if F[i][j][k]!=0*/
int F[][][];
/*characters on the left and right of output-numbers.*/
/*this will make user know which numbers are given at first.*/
char C1[][],C2[][]; /*Mark Row x and Column y,and the 3*3 grid that number 'data' has been used.*/
void Update(const int x,const int y,const int data)
{
int i,px=x/,py=y/;
for(i=;i<;++i)
{
F[x][i][data]++;/*Row*/
F[i][y][data]++;/*Column*/
F[px*+i/][py*+i%][data]++;/*Block*/
}
} /*Undo 'Update'.*/
void Undo_update(const int x,const int y,const int data)
{
int i,px=x/,py=y/;
for(i=;i<;++i)
{
F[x][i][data]--;/*Row*/
F[i][y][data]--;/*Column*/
F[px*+i/][py*+i%][data]--;/*Block*/
}
} /*Returns a pair of int (x,y) referring to the next grid should fill.*/
struct PII Get_next()
{
int i,j,k,Min=0x7fffffff;
struct PII pos;
for(i=;i<;++i)
for(j=;j<;++j)
{
if(Map[i][j])continue;
int cc=;/*to count how many numbers are not used*/
for(k=;k<=;++k)
if(!F[i][j][k])cc++;
if(cc==) { pos.x=-; return pos; }
if(cc<Min)Min=cc,pos.x=i,pos.y=j;
/*Choose the grid which has least numbers can use.*/
}
if(Min!=0x7fffffff) return pos;
pos.x=-; return pos;/*No grids can fill in*/
} int Dfs(const int rest)
{
if(rest==)
{
printf("\n\n\tSolution #%d: \n\n",++cnt);
Print(Map,C1,C2);
/*too many solutions.*/
if(cnt==) return ;
return ;
}
struct PII pos=Get_next();
if(pos.x==-) return ;
int i,list[],top=;
/*find numbers not used, and save then in 'list'.*/
for(i=;i<=;++i)
if(!F[pos.x][pos.y][i]) list[top++]=i;
for(i=;i<top;++i)
{
/*Mark that number 'i' has been used*/
Map[pos.x][pos.y]=list[i];
Update(pos.x,pos.y,list[i]); if(Dfs(rest-)) return ;
/*if Dfs retruns 1, there would be too many solutions*/
/*stop searching and return*/ /*Undo*/
Undo_update(pos.x,pos.y,list[i]);
Map[pos.x][pos.y]=;
}
return ;
} int main()
{
int op,T=;
system("cls");
printf("Choose input/output way(1.Keyboard/2.File): ");
while()/*until receiving an expected input.*/
{
scanf("%d",&op);
if(op==)break;
if(op==)
{
char File_Name[];
printf("Please input File_Name: ");
scanf("%s",File_Name);
printf("\n\tResult Will Save to Result.txt\n\n");
printf("\tCalculating....\n\n");
freopen(File_Name,"r",stdin);
freopen("Result.txt","w",stdout);
break;
}
} while()/*Support multi-set test, read to EOF.*/
{
memset(F,,sizeof(F));
memset(Map,,sizeof(Map));
cnt=;
if(op==)printf("Please Input 9*9 matrix(0 for space):\n");
int i,j,data; /*Read until EOF*/
for(i=;i<;++i) for(j=;j<;++j)
{
if(!(~scanf("%1d",&data)))
/*Only ~(-1)==0 while EOF==-1*/
{
if(op==)system("pause");
fclose(stdin);
return ;
}
Map[i][j]=data;
} int rest=;/*Update array 'F'. */
for(i=;i<;++i) for(j=;j<;++j)
if(Map[i][j]) Update(i,j,Map[i][j]),rest--; printf("Test Case #%d: ",++T); /*Check if the input is corret.*/
int f=,k;
for(i=;i<;++i)
{
for(j=;j<;++j)
{
if(Map[i][j] && F[i][j][Map[i][j]]>) { f=; break; }
if(Map[i][j])continue;
int cc=;/*Count the numbers can use in (i,j)*/
for(k=;k<=;++k)
if(!F[i][j][k])cc++;
if(cc==) { f=; break; }
}
if(j!=) break;
} /*Input error*/
if(f)
{
fprintf(stderr,"\n\t\tError in Test Case #%d: ",T);
fprintf(stderr,"Invalid Input.\n");
printf("\n\n\tFiled: No Solution Found!\n\n");
continue;
} /*if a number is known, it will be output as [x]*/
/*otherwise, there will not be the square brackets, spaces instead.*/
for(i=;i<;++i)
for(j=;j<;++j)
if(Map[i][j])C1[i][j]='[',C2[i][j]=']';
else C1[i][j]=C2[i][j]=' '; int t1=clock();/*Timer*/
if(Dfs(rest))
/*In case of costing too much time and disk storage,*/
/*Dfs(int,int) will find at most 5000 kinds of solution.*/
{
fprintf(stderr,"\n\t\tError in Test Case #%d: ",T);
fprintf(stderr,"Too much solution! Calculation has broken.\n");
} if(cnt==) printf("\n\n\tFiled: No Solution Found!\n\n");
else printf("\n\n\t%d Solution Found In %ldms.\n\n",cnt,*(clock()-t1)/CLOCKS_PER_SEC);
} return ;
}
输出函数print_sudoku.h(上面两篇代码公用):
/*
*This head defines the function to print a Sudoku by a 9*9 array
*Map[9][9] is the munber matrix,C1,C2 are the characters to print on the left and
* right side of the numbers.
*/
#include <stdio.h>
/*Function for printing the Sudoku table.*/
void Print(int Map[][],char C1[][],char C2[][])
{
printf("\t || A | B | C || D | E | F || G | H | I ||\n");
printf("\t==#########################################\n");
printf("\t1-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t--##---+---+---||---+---+---||---+---+---##\n");
printf("\t2-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t--##---+---+---||---+---+---||---+---+---##\n");
printf("\t3-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t==##===========++===========++===========##\n");
printf("\t4-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t--##---+---+---||---+---+---||---+---+---##\n");
printf("\t5-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t--##---+---+---||---+---+---||---+---+---##\n");
printf("\t6-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t==##===========++===========++===========##\n");
printf("\t7-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t--##---+---+---||---+---+---||---+---+---##\n");
printf("\t8-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t--##---+---+---||---+---+---||---+---+---##\n");
printf("\t9-##%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c||%c%d%c|%c%d%c|%c%d%c##\n",
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][], C1[][], Map[][], C2[][],
C1[][], Map[][], C2[][]);
printf("\t==#########################################\n");
return ;
}
附加几个测试数据:
[ C语言版 ] 数独计算器 [ 搜索剪枝法 ]的更多相关文章
- [NOIP2009] 靶形数独(搜索+剪枝)
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他 们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的 ...
- Luogu P1074靶形数独【搜索/剪枝】By cellur925
题目传送门 显然是一个搜索.但是开始没有任何的剪枝,暴力从\((1,1)\)点开始搜索,很自然地T了6个点. #include<cstdio> #include<algorithm& ...
- c++学习书籍推荐《清华大学计算机系列教材:数据结构(C++语言版)(第3版)》下载
百度云及其他网盘下载地址:点我 编辑推荐 <清华大学计算机系列教材:数据结构(C++语言版)(第3版)>习题解析涵盖验证型.拓展型.反思型.实践型和研究型习题,总计290余道大题.525道 ...
- 数据结构C语言版 有向图的十字链表存储表示和实现
/*1wangxiaobo@163.com 数据结构C语言版 有向图的十字链表存储表示和实现 P165 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h> ...
- 数据结构C语言版 弗洛伊德算法实现
/* 数据结构C语言版 弗洛伊德算法 P191 编译环境:Dev-C++ 4.9.9.2 */ #include <stdio.h>#include <limits.h> # ...
- HDU 1026 Ignatius and the Princess I 迷宫范围内的搜索剪枝问题
这个问题是一个典型的类型的问题迷宫广泛的搜索. 在网上看到了很多解决方案. 没什么解决问题的分析报告,不指出其中的关键点.代码更像是一大抄.一些分析师也有很大的文章分析.只是不要全部命中关键,什么是广 ...
- poj1011 搜索+剪枝
DFS+剪枝 POJ2362的强化版,重点在于剪枝 令InitLen为所求的最短原始棒长,maxlen为给定的棒子堆中最长的棒子,sumlen为这堆棒子的长度之和,那么InitLen必定在范围[max ...
- 2048小游戏代码解析 C语言版
2048小游戏,也算是风靡一时的益智游戏.其背后实现的逻辑比较简单,代码量不算多,而且趣味性强,适合作为有语言基础的童鞋来加强编程训练.本篇分析2048小游戏的C语言实现代码. 前言 游戏截图: 游 ...
- 数据结构(c语言版)代码
第1章 绪论 文档中源码及测试数据存放目录:数据结构\▲课本算法实现\▲01 绪论 概述 第一章作为绪论,主要介绍了数据结构与算法中的一些基本概念和术语.对于这些概念术语 ...
随机推荐
- 一个DBA萌新的烦恼
莫名其妙也好机缘巧合也罢,现在我成为了一名MySQL DBA. 为什么: 1.为什么leader让我转到DBA? 首先,我本身学习运维管理的时候就接触过数据库(mysql,redis),算是自身的优势 ...
- joomla建站-双语CMS系统开发的实现
首先,请确保你的网站安装了你所需的双语语言,详细安装过程见:https://www.cnblogs.com/surfer/p/9619345.html 第一步:设置内容管理 可以按照个人需求进行语言编 ...
- Vue 学习之el、template、replace和vue的生命周期 参考网址:https://segmentfault.com/a/1190000008010666
- 鸢尾花数据集-iris.data
iris.data 5.1,3.5,1.4,0.2,Iris-setosa 4.9,3.0,1.4,0.2,Iris-setosa 4.7,3.2,1.3,0.2,Iris-setosa 4.6,3. ...
- Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser]
严重: Exception sending context initialized event to listener instance of class org.springframework.we ...
- 迅为iMX6开发板支持单核,双核,四核处理器,为客户产品选择提供灵活性
本文转自迅为:http://topeetboard.com 店铺:https://arm-board.taobao.com 处理器:Freescale Cortex-A9 四核 i.MX6Q 主频 1 ...
- jQuery 超过字符截取部分用星号表示
$(function(){ var str = $('#num').text(); if (str.length >15) { var strend = str.substring(4,str. ...
- 让xamarin的Entry绑定时,支持Nullable类型
xamarin.forms默认情况下,如果属性是double?类型,绑定到Entry上,是无法实现双向绑定的, 可以自定义Converter实现双向绑定 public class NullableCo ...
- MFC如何设置窗口最前
首先,放到最前 this->SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);//使窗口总是在最前面 this->Se ...
- 【计算机网络】2.6 P2P应用
第二章第六节 P2P应用 在本节内容开始前,我们要先来对P2P架构有一个宏观的认知: P2P:(Peer to Peer 对等结构) 以对等方式进行通信,并不区分客户端和服务端,而是平等关系进行通 ...