Sudoku

搜索法解数独程序,dfs

#include <iostream>
#include <fstream>
#include <cctype>
#include <fstream>
using namespace std;
#define N 9
#define M 3
int Sudoku[N][N] = {0};
int cnt = 0;//记录解的个数
bool x[N][N] = {0};//x[i][j]代表第i行是否存在数j
bool y[N][N] = {0};//y[i][j]代表第i列是否存在数j
bool z[N][N] = {0};//z[i][j]代表第i个九宫格是否存在数j
bool flag = false;//只想输出一个解时的状态位
void Print(int Sudoku[][N])
{
	for (int i = 0; i < N;++i)
	{
		for (int j = 0; j < N;++j)
		{
			cout << Sudoku[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}
/*判断位置(i,j)是否能放置n*/
inline bool IsSafe(int i,int j,int n)
{
	return !(x[i][n] || y[j][n] || z[i / M * M + j / M][n]);
}
bool PlaceNumber(int i,int j,int n)
{
	if (IsSafe(i, j, n))
	{
		Sudoko[i][j] = n + 1;
		x[i][n] = true;
		y[j][n] = true;
		z[i / M * M + j / M][n] = true;
		return true;
	}
	else
		return false;
}
/*回朔放置程序*/
 void BackPlace(int i, int j)
{
	int n = 0;
	if (i == N)
	{
		Print(Sudoku);
		++cnt;
	}
	else if (j == N)
	{
		BackPlace(i + 1, 0);
	}
	else if (Sudoku[i][j] != 0)
		BackPlace(i, j + 1);
	else
		while (n < N)
		{
			if (PlaceNumber(i, j, n))
			{
				BackPlace(i, j + 1);
				x[i][n] = false;
				y[j][n] = false;
				z[i / M * M + j / M][n] = false;
			}
			++n;
		};
	if (n >= N && Sudoku[i][j] != 0)
		Sudoku[i][j] = 0;
}
int main()
{
	char num;
	int i = 0 ,j = 0, n = 1;
	fstream file;
	char filename[] = "Sudoku.txt";
	file.open(filename);
	/*.............................loading.............................*/
	for (i = 0;i < N;++i)
		for (j = 0;j < N;++j)
		{
			file >> num;
			if (isdigit(num))
				Sudoku[i][j] = num - '0';
			if (Sudoko[i][j] != 0)
				if (IsSafe(i, j, Sudoku[i][j] - 1))
				{
					x[i][Sudoku[i][j] - 1] = true;
					y[j][Sudoku[i][j] - 1] = true;
					z[i / M * M + j / M][Sudoku[i][j] - 1] = true;
				}
				else
				{
					cout << "input Sudoku error" << endl;
					return -1;
				}
		}
	BackPlace(0, 0);
	cout << "Total " << cnt << " answers." << endl;
	system("pause");
	return 0;
} 

Sudoko.txt文件内容示例

000070000
200050097
700000500
007000205
000060804
003080709
365009478
978546123
142030956


然后是DLX,比上面的方法效率高非常多,适合大量数据的情况

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 240000
#define BIG 0x3f3f3f3f
#define N 9
int u[MAX],d[MAX],l[MAX],r[MAX],x[MAX],y[MAX],cnt[1000],ans[100],e,deep;
char cc[100];
void rev(int m)
{
	int i,j;
	l[r[m]]=l[m];
	r[l[m]]=r[m];
	for(i=d[m];i!=m;i=d[i])
		for(j=r[i];j!=i;j=r[j])
		{
			u[d[j]]=u[j];
			d[u[j]]=d[j];
			cnt[y[j]]--;
		}
}
void rem(int m)
{
	int i,j;
	for(i=u[m];i!=m;i=u[i])
		for(j=l[i];j!=i;j=l[j])
			cnt[y[u[d[j]]=d[u[j]]=j]]++;
	l[r[m]]=r[l[m]]=m;
}
bool dfs(int dd)
{
	int i,j,mn,c;
	if(r[0]==0)
	{
		deep=dd;
		return true;
	}
	for(mn=BIG,i=r[0];i;i=r[i])
		if(mn>cnt[i])
		{
			mn=cnt[i];
			c=i;
		}
		rev(c);
		for(i=d[c];i!=c;i=d[i])
		{
			ans[dd]=x[i];
			for(j=r[i];j!=i;j=r[j])
				rev(y[j]);
			if(dfs(dd+1))
				return true;
			for(j=l[i];j!=i;j=l[j])
				rem(y[j]);
		}
		rem(c);
		return false;
}
void addu(int m)
{
	y[e]=++m;//M 为列
	cnt[y[e]]++;
	u[e]=u[m];
	d[e]=m;
	d[u[e]]=e;
	u[d[e]]=e;
	e++;
}
void add(int i,int j,int n)
{
	x[e]=x[e+1]=x[e+2]=x[e+3]=i*N*N+j*N+n;//值。。。。。?!
	l[e+1]=r[e+3]=e;
	l[e+2]=r[e]=e+1;
	l[e+3]=r[e+1]=e+2;
	l[e]=r[e+2]=e+3;
	addu(i*N+n);
	addu(N*N+j*N+n);
	addu(2*N*N+((i/3)*3+j/3)*N+n);
	addu(3*N*N+i*N+j);
}
int main()
{
	freopen("Sudoku.in", "r", stdin);
	freopen("Sudoku.out", "w", stdout);
	int a,b;
	int i,j,k;
	while(scanf("%s",cc))
	{
		if(cc[0]=='e')
			break;
		memset(cnt,0,sizeof(cnt));
		for(e=4*N*N+1,i=0;i<e;i++)
		{
			u[i]=d[i]=i;
			l[i]=(i+e-1)%e;
			r[i]=(i+1)%e;
		}
		for(i=0;i<N;i++)
			for(j=0;j<N;j++)
				if(cc[i*N+j]=='.')
					for(k=0;k<N;k++)
						add(i,j,k);
				else
					add(i,j,cc[i*N+j]-'1');
		dfs(0);
		for(i=0;i<deep;i++)
			cc[ans[i]/N]=ans[i]%N+'1';
		puts(cc);
	}
	system("pause");
	return 0;
}

Sudoku.in存放每行数据

读入end程序结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值