数独这个游戏大家都知道吧:玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3×3)内的数字均含1-9,不重复。
为了更好的区分已填和未填的格子,未填的格子用0表示!!
1.输入
int a[11][11];
int alltheanswer;//所有的解
int wanttheanswer;//期望得到的解数
int main()
{
printf("请输入9*9的数独:\n");
for(int i=1; i<=9; i++)
for(int j=1; j<=9; j++)
scanf("%d",&a[i][j]);
printf("请输入你期望得到的解数:\n");
cin>>wanttheanswer;
}
2.检查每一行是否有重复
bool checkx(int x) {//x为第几行
for(int i=1; i<=9; i++) {
if(a[x][i]==0)
continue;
for(int j=1; j<i; j++)
if(a[x][i]==a[x][j])
return false;
}
return true;
}
3.检查每一列是否有重复
bool checky(int y) { //y为第几列
for(int i=1; i<=9; i++) {
if(a[i][y]==0)
continue;
for(int j=1; j<i; j++)
if(a[i][y]==a[j][y])
return false;
}
return true;
}
4.检查每一个九宫格是否满足条件
bool jggfz(int x,int y) {//辅助判断
for(int i=x; i<x+3; i++) {
for(int j=y; j<y+3; j++) {
if(a[i][j]==0)
continue;
for(int ii=x; ii<i; ii++) {
for(int jj=y; jj<y+3; jj++) {
if(a[i][j]==a[ii][jj])
return false;
}
}
}
}
return true;
}
bool jgg() { //九宫格判断
if(jggfz(1,1)==false)
return false;
if(jggfz(4,1)==false)
return false;
if(jggfz(7,1)==false)
return false;
if(jggfz(1,4)==false)
return false;
if(jggfz(4,4)==false)
return false;
if(jggfz(7,4)==false)
return false;
if(jggfz(1,7)==false)
return false;
if(jggfz(4,7)==false)
return false;
if(jggfz(7,7)==false)
return false;
return true;
}
5.进行搜索与回溯
void dfs(int na,int nb) { //第几行第几个
if(na==10) {
if(jgg()==true) {
alltheanswer++;
if(wanttheanswer>=alltheanswer) {
printf("\n");
printf("此题解%d\n",alltheanswer);
for(int i=1; i<=9; i++) {
for(int j=1; j<=9; j++) {
if((i==4&&j==1)||(i==7&&j==1))
printf(" -------------------\n");
else if(j==4||j==7)
printf("|");
printf("%2d",a[i][j]);
}
printf("\n");
}
}
return;
}
}
if(a[na][nb]!=0) {//特殊情况
int nna=na,nnb=nb;
if(nb==9)
na++,nb=1;
else
nb++;
dfs(na,nb);
na=nna,nb=nnb;
return;
}
for(int i=1; i<=9; i++) {
a[na][nb]=i;
if(checkx(na)==false||checky(nb)==false||jgg()==false) {
a[na][nb]=0;
continue;
}
int nna=na,nnb=nb;
if(nb==9)
na++,nb=1;
else
nb++;
dfs(na,nb);
na=nna,nb=nnb;
a[nna][nnb]=0;
}
}
【整体代码如下】
#include<bits/stdc++.h>//数独
using namespace std;
int a[11][11];
int alltheanswer;
int wanttheanswer;
bool checkx(int x) {//每行是否会重复
for(int i=1; i<=9; i++) {
if(a[x][i]==0)
continue;
for(int j=1; j<i; j++)
if(a[x][i]==a[x][j])
return false;
}
return true;
}
bool checky(int y) { //每列是否会重复
for(int i=1; i<=9; i++) {
if(a[i][y]==0)
continue;
for(int j=1; j<i; j++)
if(a[i][y]==a[j][y])
return false;
}
return true;
}
bool jggfz(int x,int y) {//根据jgg中输入的行和列,判断这个九宫格是否会发生冲突
for(int i=x; i<x+3; i++) {
for(int j=y; j<y+3; j++) {
if(a[i][j]==0)
continue;
for(int ii=x; ii<i; ii++) {
for(int jj=y; jj<y+3; jj++) {
if(a[i][j]==a[ii][jj])
return false;
}
}
}
}
return true;
}
bool jgg() { //判断每个九宫格是否会发生冲突,具体看函数jggfz()
if(jggfz(1,1)==false)
return false;
if(jggfz(4,1)==false)
return false;
if(jggfz(7,1)==false)
return false;
if(jggfz(1,4)==false)
return false;
if(jggfz(4,4)==false)
return false;
if(jggfz(7,4)==false)
return false;
if(jggfz(1,7)==false)
return false;
if(jggfz(4,7)==false)
return false;
if(jggfz(7,7)==false)
return false;
return true;
}
void dfs(int na,int nb) { //第几行第几个
if(na==10) {
if(jgg()==true) {
alltheanswer++;
if(wanttheanswer>=alltheanswer) {
printf("\n");
printf("此题解%d\n",alltheanswer);
for(int i=1; i<=9; i++) {
for(int j=1; j<=9; j++) {
if((i==4&&j==1)||(i==7&&j==1))
printf(" -------------------\n");
else if(j==4||j==7)
printf("|");
printf("%2d",a[i][j]);
}
printf("\n");
}
}
return;
}
}
if(a[na][nb]!=0) {//这个位置的数已经填过了,直接填下一个数
int nna=na,nnb=nb;
if(nb==9)
na++,nb=1;
else
nb++;
dfs(na,nb);
na=nna,nb=nnb;
return;
}
for(int i=1; i<=9; i++) {//选择填什么数字:1~9
a[na][nb]=i;
if(checkx(na)==false||checky(nb)==false||jgg()==false) {//检查这一行,这一列,这一个九宫格填这个数字是否发生冲突
a[na][nb]=0;
continue;
}
int nna=na,nnb=nb;//保存开始的行,列
//更新na,nb为下一个要填的位置
//普通:nb+1
//应为nb的范围为1~9所以当nb=9时就是要填下一行了,所以na+1
if(nb==9)
na++,nb=1;
else
nb++;
dfs(na,nb);//填下一个数字
na=nna,nb=nnb;//将开始的值返回
a[nna][nnb]=0;
}
}
int main() {
printf("请输入9*9的数独:\n");
for(int i=1; i<=9; i++)
for(int j=1; j<=9; j++)
scanf("%d",&a[i][j]);
printf("请输入你期望得到的解数:\n");
cin>>wanttheanswer;
dfs(1,1);
printf("此题所有解为:%d\n\n",alltheanswer);
printf("--------------------------\n");
printf("按Enter键退出\n");
char a;//等待退出
a=getchar();
a=getchar();
return 0;
}
代码测试:
不方便执行c++代码的这边是.exe文件的下载地址:
链接:https://pan.baidu.com/s/1aA0ahZpZx2x0bVxjvSmL7g
提取码:1234
(已经达到期望题解,答案不输出但一直输出换行的BUG已修复)
但是,感觉这个代码运行的速度太慢了,所以我优化了一下,上面的代码比较好理解
代码如下:
#include<bits/stdc++.h>//数独
using namespace std;
int a[11][11];
int b[11];//每行已知数最多
int bid[11];//b的id
int bbid;//bid第几个
int c[11];//每列已知数最多
int cid[11];//c的id
int ccid;//cid第几个
int maxx;
int alltheanswer;
int wanttheanswer;
bool checkx(int x) {//x为第几行
for(int i=1; i<=9; i++) {
if(a[x][i]==0)
continue;
for(int j=1; j<i; j++)
if(a[x][i]==a[x][j])
return false;
}
return true;
}
bool checky(int y) { //y为第几列
for(int i=1; i<=9; i++) {
if(a[i][y]==0)
continue;
for(int j=1; j<i; j++)
if(a[i][y]==a[j][y])
return false;
}
return true;
}
bool jggfz(int djgg) {
int x,y;
if(djgg==1)
x=1,y=1;
else if(djgg==2)
x=1,y=4;
else if(djgg==3)
x=1,y=7;
else if(djgg==4)
x=4,y=1;
else if(djgg==5)
x=4,y=4;
else if(djgg==6)
x=4,y=7;
else if(djgg==7)
x=7,y=1;
else if(djgg==8)
x=7,y=4;
else
x=7,y=7;
for(int k=1; k<=9; k++) {
bool f=false;
for(int i=x; i<x+3; i++) {
for(int j=y; j<y+3; j++) {
if(a[i][j]==0)
continue;
if(a[i][j]==k&&f==false)
f=true;
else if(a[i][j]==k)
return false;
}
}
}
return true;
}
void dfs(int na,int nb) { //第几行第几个
if(bbid==10) {
alltheanswer++;
if(wanttheanswer>=alltheanswer) {
printf("\n");
printf("此题解%d\n",alltheanswer);
for(int i=1; i<=9; i++) {
for(int j=1; j<=9; j++) {
if((i==4&&j==1)||(i==7&&j==1))
printf(" -------------------\n");
else if(j==4||j==7)
printf("|");
printf("%2d",a[i][j]);
}
printf("\n");
}
}
return;
}
if(a[na][nb]!=0) {
int nna=na,nnb=nb,bbidd=bbid,ccidd=ccid;
if(ccid==9)
bbid++,ccid=1;
else
ccid++;
dfs(bid[bbid],cid[ccid]);
na=nna,nb=nnb,bbid=bbidd,ccid=ccidd;
return;
}
for(int i=1; i<=9; i++) {
a[na][nb]=i;
int xx,yy;
int djgg=(na-1)/3*3+(nb-1)/3+1;//第几个九宫格
if(checkx(na)==false||checky(nb)==false||jggfz(djgg)==false) {
a[na][nb]=0;
continue;
}
int nna=na,nnb=nb,bbidd=bbid,ccidd=ccid;
if(ccid==9)
bbid++,ccid=1;
else
ccid++;
dfs(bid[bbid],cid[ccid]);
na=nna,nb=nnb,bbid=bbidd,ccid=ccidd;
a[nna][nnb]=0;
}
}
int main() {
printf("请输入9*9的数独:\n");
for(int i=1; i<=9; i++) {
for(int j=1; j<=9; j++) {
scanf("%d",&a[i][j]);
if(a[i][j]!=0)
b[i]++;
if(a[j][i]!=0)
c[i]++;
}
}
//哪行已知数最多从哪行开始填,哪列已知数多从那列开始填
for(int i=1; i<=9; i++)
bid[i]=i,cid[i]=i;
for(int i=1; i<=9; i++) {
for(int j=1; j<=9-i; j++) {
if(b[j]<b[j+1])
swap(b[j],b[j+1]),swap(bid[j],bid[j+1]);
if(c[j]<c[j+1])
swap(c[j],c[j+1]),swap(cid[j],cid[j+1]);
}
}
printf("请输入你期望得到的解数:\n");
cin>>wanttheanswer;
dfs(bid[++bbid],cid[++ccid]);
printf("此题所有解为:%d\n\n",alltheanswer);
printf("--------------------------\n");
printf("按Enter键退出\n");
char a;//等待退出
a=getchar();
a=getchar();
return 0;
}
代码测试:
因为搜索的顺序不一样,所以解的输出顺序可能和第一个代码不一样。
下面是这个代码的.exe文件的下载地址:
链接:https://pan.baidu.com/s/1rWA2mxVqp4DxJp4lh73Z9w
提取码:1234