数独-dfs求解-回溯法

使用三个flag作为判断数独是否满足数独性质。

flag1:row[10][9],其中row[0][*]不使用。row[n][x]它代表的意思是,数字n在第x行是否出现过。

flag2:column[10][9],其中column[0][*]不使用。column[n][y]它代表的意思是,数字n在第y列是否出现过。

flag3:cell[10][9],其中cell[0][*]不使用。cell[n][k]它代表的意思是,数字n在第k个小小宫格(我的是这样标记:从左到右,从上到下)是否出现过。

dfs的参数有x,y。代表现在填的数字是在x,y位置。

dfs伪代码原理:

1. 如果全部填完,那么该数独的这种填法就是其中一种解,输出该数独解。

2.如果还没填完,填到了第x,y位置,判断该位置是否有数字(原题该位置有就有,没有就没有),如果有,填下一个位置。

如果没有,寻找1-9数字在三个flag中为0的数字。找到了,标记flag(3个)为1,填下一个位置。

3.回溯法是恢复之前的flag和数据,即恢复为0,因此,每次填完数字,即在尝试该数据填完后,恢复flag和原来的数独数字

c++的代码如下:

// shudu.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"//你可能需要删除掉这个
#include <iostream>
using namespace std;
int row[10][9];
int column[10][9];
int cell[10][9];
int data1[9][9];
/*
初始标记
*/
void init() {
	for (int i = 1; i < 10; i++) {
		for (int j = 0; j < 9; j++) {
			data1[i-1][j]=row[i][j] = column[i][j] = cell[i][j] = 0;
		}
	}
}
/*
显示数独
*/
void showShudu() {
	cout << "The result:" << endl;
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (j != 0) cout << " ";
			cout << data1[i][j];
		}
		cout << endl;
	}
	cout << "-----------------" << endl;
}
int count1 = 0;
/*
dfs暴力求解
*/
void  solve(int x,int y) {
	if (x >= 9) {
		count1++;
		showShudu();
		cin.get();
		return;
	}
	int nextY = (y + 1) % 9;
	int nextX = x + (y + 1) / 9;
	if (data1[x][y] != 0) {
		solve(nextX, nextY);
		return;
	}
	for (int i = 1; i < 10; i++) {
		if (row[i][x]) continue;
		if (column[i][y]) continue;
		if (cell[i][x / 3 * 3 + y / 3]) continue;
		row[i][x] = column[i][y] = cell[i][x / 3 * 3 + y / 3] = 1;
		data1[x][y] = i;
		solve(nextX,nextY);
		row[i][x] = column[i][y] = cell[i][x / 3 * 3 + y / 3] = 0;//回溯法,只能放在这里咯
	}
	data1[x][y] = 0;//这也是回溯法,没有这个不行,但为什么可以放在这里?当然也可以放在上面循环里面去
                        //放在这里可以减少计算量喽
 }
/*
读取数独题目,从filename文件读取
*/
void  setShudu(const char *filename) {
	FILE *fp = fopen(filename, "r");
	int * dataP = *data1;//看不懂???
	for (int i = 0; i < 81; i++) fscanf(fp, "%d",dataP++);
	fclose(fp);
	for (int i = 0; i < 9; i++) {
		for (int j = 0; j < 9; j++) {
			if (data1[i][j] != 0) {
				row[data1[i][j]][i] = 1;
				column[data1[i][j]][j] = 1;
				cell[data1[i][j]][i / 3 * 3 + j / 3] = 1;
			}
		}
	}
}
void startShudu() {
	init();
	setShudu("1.txt");//数独题目放在1.txt里面(有81个数字0-9,其中0代表未填)
	solve(0, 0);//从位置0,0开始
}
int main()
{
	startShudu();
        return 0;
}

文本1.txt测试样例:

3 0 2 7 5 6 4 1 8
0 0 8 0 0 0 0 0 6
0 0 7 0 4 1 2 0 3

5 0 6 0 3 9 7 0 2
1 0 9 0 7 8 6 0 5
0 0 4 0 0 0 0 0 1

2 0 3 5 8 4 1 6 9
9 0 0 0 0 0 0 0 0
0 0 0 9 0 7 3 5 4

结果如下:

基本秒出结果。

这里我的代码有些漏洞,没有在读取数独数据时检测是否合法数独(正常来说,你也不会随便拿81个数字测试吧。。。)

如果你输入一开始就是个非法数独,解出很可能是error或者等很久。

猜你喜欢

转载自blog.csdn.net/qq_30167299/article/details/80296180