c语言编写的解数独程序

c语言编写的解数独程序,第1张

#include <windows.h>

#include <stdio.h>

#include <time.h>

char sd[81]

bool isok = false

//显示数独

void show()

{

if (isok) puts("求解完成")

else puts("岁洞初始化完成")

for (int i = 0i <81i++)

{

putchar(sd[i] + '0')

if ((i + 1) % 9 == 0) putchar('\n')

}

putchar('\n')

}

//读取数独

bool Init()

{

FILE *fp = fopen("in.txt", "rb")

if (fp == NULL) return false

fread(sd, 81, 1, fp)

fclose(fp)

for (int i = 0i <81i++)

{

if (sd[i] >= '1' &&sd[i] <= '9'历洞) sd[i] -= '0'

else sd[i] = 0

}

show()

return true

}

/肢雀枯/递归解决数独

void force(int k)

{

if (isok) return

if (!sd[k])

{

for (int m = 1m <= 9m++)

{

bool mm = true

for (int n = 0n <9n++)

{

if ((m == sd[k/27*27+(k%9/3)*3+n+n/3*6]) || (m == sd[9*n+k%9]) || (m == sd[k/9*9+n]))

{

mm = false

break

}

}

if (mm)

{

sd[k] = m

if (k == 80)

{

isok = true

show()

return

}

force(k + 1)

}

}

sd[k] = 0

}

else

{

if (k == 80)

{

isok = true

show()

return

}

force(k + 1)

}

}

int main()

{

system("CLS")

if (Init())

{

double start = clock()

force(0)

printf("耗时%.0fms", clock() - start)

}

else puts("初始化错误")

getchar()

}

前两天刚写完,还没优化,已运行通过了.

晕,一维的好麻烦,这个也是碰巧前两天刚写好的,你看着自喊搭举己修改枝陵下

#include <stdio.h>

typedef struct

{

int line

int row

int num

}Node

int main()

{

/*

int a[9][9]={

{4,0,3,6,0,0,0,0,0},

{0,0,0,0,0,1,0,2,4},

{0,1,0,0,4,0,5,0,0},

{0,0,0,9,0,4,0,6,0},

{3,0,2,0,0,0,4,0,9},

{0,7,4,1,0,3,0,0,0},

{0,0,1,0,9,0,0,4,0},

{2,4,0,3,0,0,0,0,0},

{0,0,0,4,0,8,2,0,7}}

*/

int a[9][9]={

{0,0,0,8,0,0,0,6,0},

{8,7,0,0,0,0,0,0,0},

{2,9,0,0,4,1,0,0,5},

{0,0,5,7,0,0,0,0,9},

{0,2,0,0,0,0,0,1,0},

{9,0,0,0,0,4,3,0,0},

{7,0,0,6,1,0,0,9,8},

{0,0,0,0,0,0,0,5,2},

{0,6,0,0,0,9,0,0,0}}

/*

int a[9][9]={

{0,2,0,0,6,0,0,0,0},

{0,9,0,4,0,5,1,3,0},

{0,0,8,7,0,0,0,0,5},

{6,0,0,3,0,0,4,0,0},

{0,0,0,9,0,6,0,0,0},

{0,0,7,0,0,1,0,0,3},

{4,0,0,0,0,7,3,0,0},

{0,8,5,2,0,4,0,7,0},

{0,0,0,0,9,0,0,1,0}}

*/

/*

int a[9][9]={

{0,0,3,0,2,0,0,0,6},

{0,0,2,0,9,0,0,0,4},

{7,0,0,8,0,0,2,0,3},

{0,8,0,0,7,0,5,0,0},

{0,7,0,1,0,6,0,3,0},

{0,0,0,2,0,0,0,9,0},

{4,0,6,0,0,8,0,0,5},

{6,0,0,0,4,0,3,0,0},

{9,0,0,0,1,0,7,0,0}}

*/

int i,j,n,en,flag,y,k=0,x,qu,p,q

Node b[70]

for(i=0i<9i++)

{

for(j=0j<9j++)

{

if(!a[i][j])

{

b[k].line=i

b[k].row=j

b[k].num=0

k+=1

}

}

}

en=k

/*从b[0]开始试,若b[k].num>9,则k-1,否则k+1*/

for(k=0k<en)

{

++b[k].num

i=b[k].line

j=b[k].row

a[i][j]=b[k].num

n=0

while(n<9&&b[k].num<=9)

{

if(n==i)

{

for(y=0y<9y++)

{

if(y==j)

continue

if(a[n][y]==a[i][j])

flag=1

}

}

else if(n==j)

{

for(y=0y<9y++)

{

if(y==i)

continue

if(a[y][n]==a[i][j])

flag=1

}

}

/*判断同一块中有郑碧没有相同值*/

qu=3*(i/3)+j/3

switch(qu)

{

case 0:x=0

y=0

break

case 1:x=0

y=3

break

case 2:x=0

y=6

break

case 3:x=3

y=0

break

case 4:x=3

y=3

break

case 5:x=3

y=6

break

case 6:x=6

y=0

break

case 7:x=6

y=3

break

default :x=6

y=6

break

}

p=x

q=y

for(x<p+3x++)

{

for(y<q+3y++)

{

if(x==i&&y==j)

continue

if(a[x][y]==a[i][j])

{

flag=1

break

}

}

if(flag==1)

break

}

if(flag==1)

{

a[i][j]=++b[k].num

flag=0

n=0

continue

}

n++

}

if(b[k].num>9)

{

a[i][j]=b[k].num=0

k--

if(k<0)

{

printf("error!\r\n")

return -1

}

}

else

k++

}

for(i=0i<9i++)

{

for(j=0j<9j++)

{

printf("%d",a[i][j])

}

printf("\r\n")

}

return 1

}

数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。

解题手法

依解题填制的过程可区分亩吵为直观法与候选数法。

直观法就是不做任何记号,直接从数独的盘势观察线索,推论答案的方法。

候选数法就是删减等位群格位已出现的数字,将剩余可填数字填入空格做为解题线索的参考,可填数字称为候选数(Candidates,或称备选数)。

直观法和候选数法只是填制时候是否有注记的区别,依照个人习惯而定,并非鉴定题目难度或技巧难度的标准,无论是难题或是简单题都可上述方法填制,一般程序解题以候选数法较多。

摒除法

摒除法:用数字去找单元内唯一可填空格,称为摒除法,数拆耐陵字可填唯一空格称为摒余解(Hidden Single)。

根据不同的作用范围,摒余解可分为下述三种:

数字可填唯一空格在「宫」单元称为宫摒余解(Hidden Single in Box),这种解法称宫摒除法。

数字可填唯一空格在「行」单元称为行摒余解(Hidden Single in Row),这种解法称行摒除法。

数字可填唯一空格在「列」单元称为列摒余解(Hidden Single in Column),这种解法称列摒除法。

行摒余解和列摒余解合称行列摒余解(Hidden Single in Line)。

得到行列摒余解的方法称为行列摒除法。

余数法

Peer等位群格位

余数法:用格位去找唯一可填数字,称为余数法,格位唯一可填数字称为唯余解(Naked Single)。

余数法是删减等位群格位(Peer)已出现的数字的方法,每一格位的等位群格位有 20 个,如图七所示。

进阶解法

上述方法称为基础解法(Basic Techniques),其他所有的解法称为进阶解法(Advanced Techniques),是在补基本解法之不足,所以又称辅助解法。

进阶解法包括:区块摒除法(Locked Candidates)、数组法(Subset)、四角对角线(X-Wing)、唯一矩形(Unique Rectangle)、全双值坟墓(Bivalue Universal Grave)、单数链(X-Chain)、异数链(XY-Chain)及其他数链的高级技巧等等。已发展出来的方法有近百种之多。

其中前三种加上基础解法为一般数独书中介绍并使用的方法,同时也是大部分人可以理解并掌握的数独解题技法。

通过基础解法出数只需一种解法,摒除法或唯余法,超出此范围而需要施加进阶解法时,解题点需要进阶解法协助基础解法来满足隐性唯一或显性唯一才能出数,该解题点的解法需要多个步骤协力完成,因此称做组合解法。

解题必须以逻辑为依归,猜测的方法被称为暴力型解法(Brute Force),这不是提倡数独的本意。

区块摒除法

区块摒除法包括宫区块摒除法(Pointing)与行列区块摒除法(Claiming)。

在基础题里,利用区块摒除可以替代一些基础解法的观察,或辅助基础解法寻找焦点。

在非基础题里,区块可以隐藏任何其他结构,简单的可以把基础解法隐藏起来,难的可以隐藏数对等等其他进阶技巧。

区块摒除法

首先数字6对第五宫摒除,得到第五宫的6在R4C5或者R6C5。

不论是在R4C5或者R6C5,C5的其他格都不能再有数字6。(R4C5与R6C5就是数字6的区块,这也是区块摒除作用的观点)

数字6对第二宫摒除,得解R1C4=6。

数对法

当一个单元(行、列、宫)的某两个数字仅可能在某两格时,我们称这两个格为这两个数的数对(Pairs)。

数对出现在宫称为宫数对;数对出现在行列成为行列数对。

用候选数法的观点去看,数对有两种,一种是在同单元内其中两格有相同的双候选数,一看就明白,因此称为显性数对(Naked Pair),另一种是,同单元内有两个候选数旅戚占用了相同的两格,该两格因为还有其它候选数很难辨认,因此称为隐性数对(Hidden Pair)。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12337301.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存