想要解數獨,通常是用「試誤法」,就是一格一格試
若不符合,則退一格再試,一直試到結束。
#include<stdio.h>
#include<stdlib.h>
int sodoku[10][10],post[10][10][2],cnt[82],blank[82][2] ; //sodoku是數獨表,post[i][j][0 or 1]記錄第(i,j)格屬於的宮的開頭坐標,cnt[i]是指第i個未知數目前被嘗試放入的數字,blank[i][0 or 1]分別代表待解之數的x和y坐標
int n,i,j,k,kx,ky,index,to,pass,fin ;
int pos(int x,int y) ;
int chk(int x,int y) ;
void prt(void) ;
int pos(int x,int y){
int xy = 0 ;
if(x <= n){
xy = 10 ;
}else if(n == 2){
xy = 30 ;
}else if(n == 3){
if(x > n * 2)xy = 70 ;
else xy = 40 ;
}
if(y <= n){
xy += 1 ;
}else if(n == 2){
xy += 3 ;
}else if(n == 3){
if(y > n * 2)xy += 7 ;
else xy += 4 ;
}
return xy ;
}
int chk(int x,int y){ //檢查目前的sodoku是否合法
int ix,iy ;
for(ix = 1 ; ix <= n * n ; ix++){
if(ix != x && sodoku[ix][y] == sodoku[x][y])return 0 ;
}
for(iy = 1 ; iy <= n * n ; iy++){
if(iy != y && sodoku[x][iy] == sodoku[x][y])return 0 ;
}
for(ix = post[x][y][0] ; ix < post[x][y][0] + n ; ix++){
for(iy = post[x][y][1] ; iy < post[x][y][1] + n ; iy++){
if(ix != x && iy != y && sodoku[ix][iy] == sodoku[x][y])return 0 ;
}
}
return 1 ;
}
void prt(void){
int ix,iy ;
for(ix = 1 ; ix <= n * n ; ix++){
for(iy = 1 ; iy <= n * n ; iy++){
printf("%d ",sodoku[ix][iy]) ;
}
printf("\n") ;
}
printf("\n") ;
//system("pause") ;
}
int main()
{
while(scanf("%d",&n)!=EOF){
to = index = 0 ;
for(i = 1 ; i <= n * n ; i++) //先讀資料(在此只考慮n<=3的情況)
for(j = 1 ; j <= n * n ; j++){
scanf("%d",&sodoku[i][j]) ;
if(!sodoku[i][j]){ // 若讀到0,則表示這格是待解的數
blank[to][0] = i ;
blank[to][1] = j ;
to += 1 ;
}
}
for(i = 1 ; i <= n * n ; i++){//記錄第i列第j行是屬於哪一宮(以n=3來說,就是指九宮格)
for(j = 1 ; j <= n * n ; j++){
post[i][j][0] = pos(i,j) / 10 ;
post[i][j][1] = pos(i,j) % 10 ;
}
}
pass = 1 ;
for(i = 1 ; i <= n * n ; i++){
for(j = 1 ; j <= n * n ; j++){
if(sodoku[i][j]){
if(!chk(i,j)){
pass = 0 ;
break ;
}
}
}
if(!pass)break ;
}
if(!pass){
printf("NO SOLUTION\n") ;
}else{
cnt[0] = 0 ;
for(index = 0;;){ //開始一個一個跑
if(cnt[index] < n * n){
cnt[index] += 1 ;
sodoku[blank[index][0]][blank[index][1]] = cnt[index] ;
if(chk(blank[index][0],blank[index][1])){
if(index < to - 1){
index += 1 ;
cnt[index] = 0 ;
}else{
prt() ; //找到了,print出來
fin = 1 ;
break ;
}
}
}else{
if(!index){
if(!fin)printf("NO SOLUTION\n") ; //找不到,輸出NO SOLUTION
break ;
}else{
sodoku[blank[index][0]][blank[index][1]] = 0 ;
index -= 1 ;
}
}
} //for(index;;)的右中括號
} //if(!pass)的右中括號
} //while(scanf("%d",&n)!=EOF)的右中括號
//system("pause") ;
return 0 ;
}
全部都是未知數的話,找到一組字典順序在最前面的。
沒有留言:
張貼留言