九宫格数独,是一个9*9的格子里,填上1-9的数,规则如下:
1.每一行不能有重复的值
2.每一列不能有重复的值
3.每个宫内不能有重复的值
宫的意思是每三个行、列的9个方格为宫
以下为实现代码,有详细的注释:
导入的题目文件名要和代码中“shudutimu.txt”一致,里面的数组格式可以用逗号、顿号、空格,甚至不分隔也可以,代码自动处理成一个81个数的数组。
保存结果的文件自动生成。
#include <stdio.h>
int qw[81]; //导入的题目存放数组
int aa[81]; //定义一个数组做草稿
int flag,end; //数据更改过的标志和结束标志
int start; //起始数据位,用于判断是否可解
/* 导入题目 */
void qw_load(void)
{
int ch;
int n=0;
FILE* pf = fopen("shudutimu.txt","r"); //导入txt题目文件
while((ch = fgetc(pf)) != EOF)
{
if(ch>='0' && (ch<='9'))
{
qw[n]=ch-48; //ASCII码字符转数字,再放入题目数组
n++;
}
}
fclose(pf);
}
/* 保存结果 */
void result(void)
{
int i,j;
FILE* pf_rs = fopen("result.txt","w"); //创捷或打开保存结果txt文档
if(end==0) //如果有解,打印结果
{
for(i=0;i<9;i++)
{
for(j=0;j<9;j++)
{
fprintf(pf_rs, "%d", aa[i*9+j]);
if(j==2||j==5)
fprintf(pf_rs, "%s", " | ");
else
fprintf(pf_rs, "%s", " ");
}
fprintf(pf_rs, "%s","\n");
if(i==2||i==5)
fprintf(pf_rs, "%s","- - - - - - - - - - - - - -\n");
}
}
else
{
fprintf(pf_rs, "%s", "此题无解!");
}
fclose(pf_rs); //关闭txt文档
}
/* 查询当前数字的行、列、宫中有没有重复值 */
void check(int n)
{
int a,b,i,j;
int col,row;
col=n/9; //一维数组转二维数组的列,就是除以9
row=n%9; //一维数组转二维数组的行,就是9的余数
if(aa[n]==0)
{
aa[n]=1; //如果值为0,先赋初值为1,再去判断是否有重复
}
for(a=0;a<9;a++)
{
if((col*9+a)!=n) //查询行中的数据,判断时要避开当前值
{
if(aa[n]==aa[col*9+a]) //如果查询到有重复值
{
aa[n]=aa[n]+1; //当前值加1
flag=1; //数据更改变为置1,表示已更改过数据
} //需要再查询一次,以保证更改后的数据没有重复
}
}
for(b=0;b<9;b++)
{
if((b*9+row)!=n) //查询列中的数据,和行的处理一样
{
if(aa[n]==aa[b*9+row])
{
aa[n]=aa[n]+1;
flag=1;
}
}
}
for(i=0;i<3;i++) //查询宫中的数据,和行、列的处理一样
{
for(j=0;j<3;j++)
{
if(((col/3*3+i)*9+row/3*3+j)!= n) //这个除以3再乘以3,看起来有点迷
{ //实际上得到的值就是回到当前值所在的宫的第一个数
if(aa[n]==aa[(col/3*3+i)*9+row/3*3+j])
{
aa[n]=aa[n]+1;
flag=1;
}
}
}
}
}
/* 当数据有更改时,再次查询,以确认没有重复值 */
void recheck(int n)
{
do
{
flag=0;
check(n);
}while(flag==1); //只要数据有更改,就一直循环,直到没有更改为止
}
void fill(int n)
{
int m;
m=n; //保存当前的位置,以便后面退回其他位置更改数据后,判断是否已经回到当前位置
do
{
recheck(n); //查询是否有重复值
while(aa[n]>9) //如果查询的结果1-9都重复,一直循环,直到符合1-9为止
{
aa[n]=0; //则将当前值初始化为0
do{
n--; //退到上一个位置
}while(qw[n]!=0); //用原始数组来判断上一个位置是否为空缺值,一直退到空缺值位置
aa[n]=aa[n]+1; //把空缺值位置上填的数再往上加
recheck(n); //查询重复值
if(n==start && aa[n]>9) //如果退到首个空缺位置,而且数据加到9了还有重复值
{
aa[n]=0; //则表示此题无解,将值置0,n置81,就可以退出循环了
n=81; //当然也可以用break退出循环,但是外面还有一层循环
end=1; //结束标志置1,表示此题无解
}
}
n++; //退了修改完值之后,再加回来,重新查询重复值
}while(n<m+1); //退回前面位置修改值后,一直循环,直到回到当前位置
}
int main()
{
int i,j;
start=0;
end = 0;
qw_load();
/* 题目写入草稿数组 */
for(i=0;i<81;i++)
{
aa[i]=qw[i];
}
/* 判断首个空值,用于后面判断题目是否有解 */
while(aa[start++]!=0);
start=start-1;
/* 开始填数 */
for(i=0;i<81;i++)
{
if(aa[i]==0)
{
fill(i);
}
if(end==1) //每次填数后,查询是否无解结束
{
break;
}
}
result();
}
题目:
显示结果: