[ 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 绪论 概述 第一章作为绪论,主要介绍了数据结构与算法中的一些基本概念和术语.对于这些概念术语 ...
随机推荐
- 438 Find All Anagrams in a String 找出字符串中所有的变位词
详见:https://leetcode.com/problems/find-all-anagrams-in-a-string/description/ C++: class Solution { pu ...
- Android开发中实现桌面小部件
详细信息请参考原文:Android开发中实现桌面小部件 在Android开发中,有时候我们的App设计的功能比较多的时候,需要根据需要更简洁的为用户提供清晰已用的某些功能的时候,用桌面小部件就是一个很 ...
- java debug源码完整版
第一步:现在myeclipse或者eclipse中下载jad插件,将class文件翻译成java文件 点击下载安装 第二步:创建一个java工程,导出成jar包.jdk自带的jar包不包含debug ...
- java内存查看与分析
业界有很多强大的java profile的工具,比如Jporfiler,yourkit,这些收费的东西我就不想说了,想说的是,其实java自己就提供了很多内存监控的小工具,下面列举的工具只是一小部分, ...
- Node.js——url模块
url模块通过api可以将get提交的参数方便的提取出来
- Asp.Net 设计模式 之 “工厂方法”即利用 接口 实现的抽象工厂
主要改动部分: /// <summary> /// 6.创建工厂方法模式(抽象工厂:接口) /// </summary> interface IFactory ...
- 当前主要的常用的PHP环境部署套件比较
当前主要的常用的PHP环境部署套件比较 作为新手,需要学习PHP,或者需要搭建PHP+MySQL运行环境时,就需要去找各种搭建方法,一步一步按照操作流程操作,不仅繁琐,而且容易出错,还会带来安全隐患. ...
- SpringCloud 微服务框架
学习资源:https://ke.qq.com/course/280057 知识体系分为以下几点: 1)使用Eureka搭建注册中心,包括 服务生产者.服务消费者(也称服务注册与发现): Zookeep ...
- MFC如何设置窗口最前
首先,放到最前 this->SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);//使窗口总是在最前面 this->Se ...
- webpack遇见的坑:Please install 'webpack-cli' in addition to webpack itself to use the CLI.
webpack-cli没被找到: 在webpack4.0之后,需要全局安装webpack-cli, 在全局安装webpack之后,cnpm i webpack-cli -g 在局部使用webpack时 ...