【例题2】数独游戏

【例题2】数独游戏
题面

题目描述

数独是一种传统益智游戏,你需要把 \(9\times 9\) 的数独补充完整,使得图中每行、每列、每个 \(3\times 3\) 的九宫格内数字 \(1\sim 9\) 均恰好出现一次。

请编写一个程序填写数独。

输入格式

输入包含多组测试用例。

每个测试用例占一行,包含 \(81\) 个字符,表达数独的 \(81\) 个格内数据(顺序总体由上到下,同行由左到右)。

每个字符都是一个数字或一个 .(表示尚未填充)。

您可以假设输入中的每一个谜题都只有一个解决方案。

文件结尾处包含单词 end 的单行,表示输入结束。

输出格式

每个测试用例,输出一行数据,表示填充完全后的数独。

样例

样例输入

4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end

样例输出

417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936
分析
  • 根据题意,要填数字(废话)
  • 根据题意,\(81\) 个字符组成 \(9\times 9\) 的地图,并且地图中每行、每列、每个 \(3\times 3\) 的九宫格中的数字是 \(1\sim 9\),且不能重复,对于这一个的处理简单,用数组标记就可以了
bool a[9][9], b[9][9], c[9][9][9];

或者是用状态压缩(状压)

int a[9], b[9], c[9][9];
  • 那么剩下的就是枚举爆搜了
Code
#include <bits/stdc++.h>
using namespace std;

string s;
int maze[9][9]; // 答案数组
int mat[3][3], line[9], row[9]; // 小矩阵,行,列的数字选择判断数组 

bool dfs(int idx) {
	if (idx == 81) {
		for (int i = 0; i < 9; ++i)
			for (int j = 0; j < 9; ++j)
				cout << maze[i][j];
		cout << endl;
		return true;
	}
	
	int x = idx / 9, y = idx % 9;
	
     // 如果这个位置已经有数字了,那么直接下一个
	if (maze[x][y]) 
		return dfs(idx + 1);
	
	for (int i = 1; i <= 9; ++i) {
         // 判断没有重复数字
		if ((mat[x / 3][y / 3] >> i) & 1) continue;
		if ((line[x] >> i) & 1) continue;
		if ((row[y] >> i) & 1) continue;
		
         // 记录该小矩阵,行,列有该数字
		mat[x / 3][y / 3] |= (1 << i);
		line[x] |= (1 << i);
		row[y] |= (1 << i);
		
		maze[x][y] = i;
		
         // 如果枚举成功,那么唯一的答案已经输出了,没必要继续下去,所以剪掉剩余的所有情况
		if (dfs(idx + 1))
			return true;
		
         // 如果枚举失败,说明(x, y)这个点不适合填 i
		maze[x][y] = 0;
		
         // 将该数字从记录中排除
		mat[x / 3][y / 3] ^= (1 << i);
		line[x] ^= (1 << i);
		row[y] ^= (1 << i);
	}
	
	return false;
}

int main (void) {
	while (cin >> s && s != "end") {
		memset(maze, 0, sizeof(maze));
		memset(mat, 0, sizeof(mat));
		memset(line, 0, sizeof(line));
		memset(row, 0, sizeof(row));
		
		for (int i = 0; i < 9; ++i)
			for (int j = 0; j < 9; ++j) {
				if (s[i * 9 + j] != '.') {
					maze[i][j] = s[i * 9 + j] - 48;
					
                      // 记录该小矩阵,行,列有该数字
                      mat[i / 3][j / 3] |= (1 << (s[i * 9 + j] - 48));
					line[i] |= (1 << (s[i * 9 + j] - 48));
					row[j] |= (1 << (s[i * 9 + j] - 48));
				}
			}
		
		dfs(0);
	}
	
	return 0;
}
posted @ 2021-07-12 13:43  Juro  阅读(112)  评论(0编辑  收藏  举报