DFS求解数独算法

        以前也想过很久解数独的算法,但是没有得到很简单的方法,某天看到某位学长的代码,恍然大悟,本以为暴力搜索会很花时间(10^81种可能),没想到实际上由于各种限制,枚举次数竟然普遍小于10000次,用dfs便可实现每种可能都列举。这样计算一个数独就很快了(不到1ms),下面附上自己理解改动并加了注释的代码,DEV编译可能会效果好一些。

代码:

#include <stdio.h>
#include<stdlib.h>
#include<windows.h>
char map[9][9],xx;
int ans=0;
bool suit=false;
void position(int x,int y) {
	COORD pos={x,y};
	HANDLE Out=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(Out,pos);
}
void Hide() {
	HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);  
	CONSOLE_CURSOR_INFO CursorInfo;  
	GetConsoleCursorInfo(handle,&CursorInfo);		//获取控制台光标信息  
	CursorInfo.bVisible = false;		//隐藏控制台光标  
	SetConsoleCursorInfo(handle,&CursorInfo);		//设置控制台光标状态   
}
void print(int x,int y) {
	ans++; 
	position(y*2,x);
	printf("%d",map[x][y]);
    position(0,11);
    printf("\n已尝试:%d次\n",ans);
}
bool check(int n,int v) {
    int x=n%9;
    int y=n/9;
    for(int i=0;i<9;i++) if(map[x][i]==v||map[i][y]==v) return false;	//检验横竖
    x=x/3*3;
    y=y/3*3;
    for(int i=x;i<x+3;i++) for(int j=y;j<y+3;j++) if(map[i][j]==v) return false;	//检验九宫格
    return true;
}
void dfs(int n) {	//暴力查找 
    int x=n%9;
    int y=n/9;
    if (n==81||suit) {	//出口 
        suit=true;
        return;
    }
    if (map[x][y]!=0) dfs(n+1);
    else for(int i=1;i<=9;i++) if(check(n,i)) {
        map[x][y]=i;
        print(x,y);
        dfs(n+1);
        if(suit) return;
        map[x][y]=0;
	}
}
int main() {
	int i,j;
    freopen("1.txt","r",stdin);	//从文档读入 
    Hide();		//隐藏光标
    for (i=0;i<9;i++) {
        for (j=0;j<9;j++) {
            scanf("%c",&map[i][j]);
            map[i][j]-='0';
        }
        if(i!=8||j!=8) scanf("%c",&xx);	//读换行 
    }
    for(i=0;i<9;i++) {		//初始化屏幕
    	for(j=0;j<9;j++) printf("%d ",map[i][j]);
		printf("\n");
	}
	position(25,5);
	printf("正在求解数独。。。");
    dfs(0);
    printf("\n求解完毕!\n"); 
}

效果图:

 还可以再加一个求出所有解的动能。

 

________________________________________________________________分割线

2018.12.24更新,由于有人评论DFS并不快,不得不解释一下耗时的地方是printf语句,去掉之后1S之内完全可以解出来,之前只是为了让大家看清求解过程才去加了很多过程语句,下面是快速求解的代码:

#include <stdio.h>
#include<stdlib.h>
char map[9][9],xx;
int ans=0;
bool suit=false;
bool check(int n,int v) {
    int x=n%9;
    int y=n/9;
    for(int i=0;i<9;i++) 
		if(map[x][i]==v||map[i][y]==v) 
			return false;	//检验横竖
    x=x/3*3;
    y=y/3*3;
    for(int i=x;i<x+3;i++) 
		for(int j=y;j<y+3;j++) 
			if(map[i][j]==v) 
				return false;	//检验九宫格
    return true;
}
void dfs(int n) {	//暴力查找 
    int x=n%9;
    int y=n/9;
    if (n==81||suit) {	//出口 
        suit=true;
        return;
    }
    if (map[x][y]!=0) 
		dfs(n+1);
    else 
		for(int i=1;i<=9;i++) 
			if(check(n,i)) {
        		map[x][y]=i;
        		dfs(n+1);
        		if(suit) return;
        		map[x][y]=0;
			}
}
int main() {
	int i,j;
    freopen("1.txt","r",stdin);	//从文档读入 
    for (i=0;i<9;i++) {
        for (j=0;j<9;j++) {
            scanf("%c",&map[i][j]);
            map[i][j]-='0';
        }
        if(i!=8||j!=8) 
			scanf("%c",&xx);	//读换行 
    }
    dfs(0);	//求解 
    for(int i=0;i<9;i++) {	//输出答案 
    	for(int j=0;j<9;j++) {
    		printf("%d ",map[i][j]);
		}
		printf("\n");
	}
    system("pause"); 
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值