【数独C语言】:
1.行、宫、列进行判断下的正推方法(不用回溯法)可以解决大部分问题;
2.使用回溯法递归方式解决剩下的情况(效率很不错);
#ifndef __SUDOKU_H_ #define __SUDOKU_H__ #include<stdio.h> int SUDOKUarr[9][9] = { //临时数组,作为测试题目,或示范 {0,4,2,0,6,3,0,0,9}, {6,0,0,0,1,0,0,0,5}, {3,0,0,0,2,0,4,8,0}, {1,0,0,5,0,2,6,0,8}, {4,0,0,0,0,7,0,0,1}, {9,0,5,6,0,0,0,0,7}, {0,3,6,0,5,0,0,0,2}, {2,0,0,0,7,0,0,0,4}, {7,0,0,2,9,0,8,5,0}, }; void SUDOKUinput(int arr[9][9]){ //输入和输出(输出改写为展现宫的形式) char ques[9][9]; int i,j; for(i=0;i<9;i++) scanf("%s",ques[i]); for(i=0;i<9;i++){ for(j=0;j<9;j++) arr[i][j] = (int)ques[i][j] - 48; } } void SUDOKUputout(int arr[9][9]){ int i,j,d,len = 25; printf("\n"); for(i=0;i<9;i++){ if(i%3==0){ for(d=0;d<len;d++){printf("-");} printf("\n"); } for(j=0;j<9;j++){ if(j%3==0){ printf("| "); } printf("%d ",arr[i][j]); } printf("|\n"); } for(d=0;d<len;d++){printf("-");} } //对行,宫,列进行判断,是否可以填入num int SUDOKUright(int num,int x,int y){ int i,j,glie = x/3,grow = y/3; if(SUDOKUarr[x][y]!=0) return 0; for(i=3*glie;i<glie*3+3;i++){ for(j=3*grow;j<3*grow+3;j++){ if(SUDOKUarr[i][j]==num) return 0; } } for(i=0;i<9;i++){ if(SUDOKUarr[i][y]==num||SUDOKUarr[x][i]==num){ return 0; } } return 1; } int SUDOKUrightgong(int num,int glie,int grow){ int i,j; for(i=3*glie;i<glie*3+3;i++){ for(j=3*grow;j<3*grow+3;j++){ if(SUDOKUarr[i][j]==num) return 0; } } return 1; } void SUDOKUset1(){ int i,j,s,count=0,num; for(i=0;i<9;i++){ for(j=0;j<9;j++) { if(SUDOKUarr[i][j]==0){ for(s=1;s<=9;s++){ if(SUDOKUright(s,i,j)){ num = s; count++; } } if(count==1) { SUDOKUarr[i][j] = num; } } } } } void SUDOKUsetgong(int s,int glie,int grow){ int i,j,count=0,x,y; for(i=3*glie;i<glie*3+3;i++){ for(j=3*grow;j<3*grow+3;j++){ if(SUDOKUright(s,i,j)) { count++; x = i; y = j; } } } if(count==1) { SUDOKUarr[x][y] = s; } } void SUDOKUset2(){ int i,j,s; for(s=1;s<=9;s++){ for(i=0;i<3;i++){ for(j=0;j<3;j++) { if(SUDOKUrightgong(s,i,j)) SUDOKUsetgong(s,i,j); } } } } int SUDOKUrighthang(int s,int hang){ int i; for(i=0;i<9;i++){ if(SUDOKUarr[hang][i]==s){ return 0; } } return 1; } int SUDOKUrightlie(int s,int lie){ int i; for(i=0;i<9;i++){ if(SUDOKUarr[i][lie]==s){ return 0; } } return 1; } void SUDOKUsethang(int s,int hang){ int i,count = 0; for(i=0;i<9;i++){ if(SUDOKUright(s,hang,i)){ count++; } } if(count==1){ for(i=0;i<9;i++){ if(SUDOKUright(s,hang,i)){ SUDOKUarr[hang][i] = s; break; } } } } void SUDOKUsetlie(int s,int lie){ int i,count = 0; for(i=0;i<9;i++){ if(SUDOKUright(s,i,lie)){ count++; } } if(count==1){ for(i=0;i<9;i++){ if(SUDOKUright(s,i,lie)){ SUDOKUarr[i][lie] = s; break; } } } } void SUDOKUset3(){ int i,j,s; for(s=1;s<=9;s++){ for(i=0;i<9;i++){ if(SUDOKUrighthang(s,i)){ SUDOKUsethang(s,i); } } } } void SUDOKUset4(){ int i,j,s; for(s=1;s<=9;s++){ for(i=0;i<9;i++){ if(SUDOKUrightlie(s,i)){ SUDOKUsetlie(s,i); } } } } int SUDOKUgetnum(int i,int j){ int s,count = 0; for(s=1;s<=9;s++){ if(SUDOKUright(s,i,j)) count++; } return count; } void SUDOKUsetone(int i,int j){ int s; for(s=1;s<=9;s++){ if(SUDOKUright(s,i,j)) { SUDOKUarr[i][j] = s; break; } } } void SUDOKUset5(){ int i,j,s,count=0; for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(SUDOKUgetnum(i,j)==1) SUDOKUsetone(i,j); } } } void SUDOKUrun(){ //正推法,可以解决绝大多数题目而不用回溯法 int code[9][9],i,j; rerun: for(i=0;i<9;i++){ for(j=0;j<9;j++){ code[i][j] = SUDOKUarr[i][j]; } } SUDOKUset5(); SUDOKUset4(); SUDOKUset3(); SUDOKUset2(); SUDOKUset1(); for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(code[i][j] != SUDOKUarr[i][j]) goto rerun; } } } int SUDOKUspace(){ //判断空格数,是否有错等判断方法 int i,j,count = 0; for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(SUDOKUarr[i][j]==0) count++; } } return count; } int SUDOKUfault(){ int code[9]={0,0,0,0,0,0,0,0,0}; int i,j; for(i=0;i<9;i++){ for(j=0;j<9;j++){ code[SUDOKUarr[i][j]-1]++; } } for(i=0;i<9;i++){ if(code[i]!=9) return 1; code[i] = 0; } for(i=0;i<9;i++){ for(j=0;j<9;j++){ code[SUDOKUarr[i][j]-1]++; } for(j=0;j<9;j++){ if(code[i]!=0) return 1; } } return 0; } int SUDOKUwrong(){ int i,j; for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(SUDOKUarr[i][j]==0&&SUDOKUgetnum(i,j)==0) return 1; } } return 0; } //下面是回溯法,解决数独问题 //检测行,列,宫是否填入正确(无重复) int SUDOKUcheck(int n,int m){ int i,j,glie = n/3,grow = m/3,num = SUDOKUarr[n][m]; for(i=3*glie;i<glie*3+3;i++){ for(j=3*grow;j<3*grow+3;j++){ if(num==SUDOKUarr[i][j]&&!(i==n&&j==m)) return 0; } } for(i=0;i<9;i++){ if((SUDOKUarr[i][m]==num&&i!=n)||(SUDOKUarr[n][i]==num&&i!=m)) return 0; } return 1; } //最主要方法,可解决所有问题:注意回溯和递归思路!!! int SUDOKUsolve(){ int i,j,k; for(i=0;i<9;i++){ for(j=0;j<9;j++){ if(SUDOKUarr[i][j]!=0) continue; for(k=1;k<=9;k++){ SUDOKUarr[i][j] = k; if(SUDOKUcheck(i,j)&&SUDOKUsolve()) return 1; SUDOKUarr[i][j] = 0; } return 0; } } return 1; } //正式完工(或许优化,加快速度什么的) void sudoku(int ques[9][9]){ int i,j; for(i=0;i<9;i++){ for(j=0;j<9;j++){ SUDOKUarr[i][j] = ques[i][j]; } } SUDOKUrun(); if(SUDOKUspace()!=0) SUDOKUsolve(); for(i=0;i<9;i++){ for(j=0;j<9;j++){ ques[i][j] = SUDOKUarr[i][j]; } } } #endif
PS:上面写入头文件内部,下面是调用方法:
#include"SUDOKU.h"
#include<stdio.h>
int main(){
int ques[9][9];
printf("[请输入题目]\n");
SUDOKUinput(ques);
sudoku(ques);
printf("[数独解决答案]\n");
SUDOKUputout(ques);
}
实例: