数独游戏

数独游戏

【题目】

九宫格是在81个格子(9×9)中,要满足以下条件:

(1)每个横行和竖列中的9个格子都包含数字1~9,且不重复;

(2)每个黑色粗实线围住的9个格子(3×3)都包含数字1~9,且不重复。如图所示:

要求:找出给定数字的九宫格。

输入形式:输入9981个数字,其中0表示要填的数字。

输出形式:输出满足条件的九宫格。

某测试样例如下:

输入形式

输出形式

0 6 1 0 3 0 0 2 0

0 5 0 0 0 8 1 0 7

0 0 0 0 0 7 0 3 4

0 0 9 0 0 6 0 7 8

0 0 3 2 0 9 5 0 0

5 7 0 3 0 0 9 0 0

1 9 0 7 0 0 0 0 0

8 0 2 4 0 0 0 6 0

0 4 0 0 1 0 2 5 0

7 6 1 9 3 4 8 2 5

3 5 4 6 2 8 1 9 7

9 2 8 1 5 7 6 3 4

2 1 9 5 4 6 3 7 8

4 8 3 2 7 9 5 1 6

5 7 6 3 8 1 9 4 2

1 9 5 7 6 2 4 8 3

8 3 2 4 9 5 7 6 1

6 4 7 8 1 3 2 5 9

【分析】

       这里运用递归回溯。用3个二维数组记录第i行哪个数已经被使用、第j列哪个数已经被使用、第th(3 x 3)格子已经有哪些数了。这样我们就可以很快地通过二维数组判断该填入的数是否满足条件了。

       首先我们用二维数组记录给定的九宫格,并且记录未被填入数字的格子的位置,那么递归层数就为这样未被填入数字的格子的数量,这样的格子可能填入的数值均为19中其中的一个数,至于它只能填哪个数才能使得满足条件的话就应该用上述的3个二维数组进行判断了。可见这里的解空间是一棵子集树,每一层都有9种选择。当我们将数字都填入到这些位置后,便得到一个满足条件的九宫格了。

【程序】

用C++语言编写程序,代码如下:

#include<iostream>
using namespace std;
//该类用于包装需被填入数的格子的属性
class Pos {
public:
	int x, y, th;
	//x表示格子在二维数组中的行,y表示格子在二维数组中的列
	//th表示该格子位于第几个(3 x 3)格子,从左到右从上到下数依次编号,共有9个(3 x 3)格子
	Pos(int i = 0, int j = 0) {
		x = i; y = j; th = (i - 1) / 3 * 3 + (j - 1) / 3;
	}
};

int n;
int **g; //用于记录给定九宫格
bool **vis1, **vis2, **vis3;
//vis1[i][k]用于记录九宫格中的第i行的k数字是否已经被放置
//vis2[j][k]用于记录九宫格中的第j列的k数字是否已经被放置
//vis3[th][k]用于记录九宫格中的第th个(3 x 3)格子的k数字是否被放置
int count0; //记录未被给定的数字
Pos *p; //记录未被给定的数字在二维数组中的位置

//初始化所有数据
void init() {
	n = 9;
	g = new int*[n + 1];
	vis1 = new bool*[n + 1];
	vis2 = new bool*[n + 1];
	vis3 = new bool*[n + 1];

	count0 = 0;
	p = new Pos[n * n + 100];

	for (int i = 0; i <= n; i++) {
		g[i] = new int[n + 1];
		vis1[i] = new bool[n + 1];
		vis2[i] = new bool[n + 1];
		vis3[i] = new bool[n + 1]; 

		for (int j = 0; j <= n; j++)
			vis1[i][j] = vis2[i][j] = vis3[i][j] = false;
	}
}

void solve(int t) {
	if (t == count0) {
		for (int i = 1; i <= n; i++) {
			cout << g[i][1];
			for (int j = 2; j <= n; j++)
				cout << " " << g[i][j];
			cout << endl;
		}
		//return false;
		return;
	}
	int i = p[t].x, j = p[t].y, th = p[t].th;
	for (int k = 1; k <= n; k++) {
		/* 判断九宫格的第i行有没有k这个数字、判断九宫格的第j列有没有k这个数字、
		判断第th (3 x 3)格子是否已经包含k这个数字 */
		if (!vis1[i][k] && !vis2[j][k] && !vis3[th][k]) {
			g[i][j] = k;
			vis1[i][k] = vis2[j][k] = vis3[th][k] = true;
			//if (!solve(t + 1))
				//return false;
			solve(t + 1);
			g[i][j] = 0;
			vis1[i][k] = vis2[j][k] = vis3[th][k] = false;
		}
	}

	//return true;
}

int main() {
	init();
	
	int k;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> k;
			g[i][j] = k;
			if (g[i][j] != 0) {
				vis1[i][k] = vis2[j][k] = vis3[(i - 1) / 3 * 3 + (j - 1) / 3][k] = true;
			}
			else {
				p[count0] = Pos(i, j);
				count0++;
			}
		}
	}
	cout << endl;
	solve(0);
	
	return 0;
}

【结果】

输入题目所给的样例输入数据,输出正确结果:


  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值