数独有趣,爆搜无脑。

还有回不去的还记得的一张张写满算式的纸,和解不出的数独。

题目大意

标准 9×9 9 \times 9 的数独游戏,由你填上空缺的数

思路

  • 填满每个空格
  • 记录某一行,某一列,某一小格不能填的数
  • 开始爆搜

搜索

  • 搜索过程中,依次往每个格子中填数
  • 简单Hash,O(1)O(1)判断某行某列某小格是否填写某数

注意事项

  • 本题给定数据的数独矩阵,数和数之间没有空格,所以需要用字符处理。

当然为了某不愿透露姓名的PC同学的幸福生活,交完题我就更改了一下qwq

同时@PC,@SJQ

  • 需要通过行号和列号确定所在小格号

其实也可以打个表解决这种问题

inline int Getblock (int r, int c) { //r表示行,c表示列
int rr = r / 3;
int cc = c / 3;;
return rr * 3 + cc;
}

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
short r[9][10], c[9][10], block[9][10];//分别记录行、列、小格中填数的情况,r表示行,c表示列,block表示小格
int board[9][9];
struct Pos {
int r, c;
Pos(int rr, int cc): r(rr), c(cc) { }
};
vector<Pos> blank;//结构体+Vector记录空白格
inline int Getblock (int r, int c) {
int rr = r / 3;
int cc = c / 3;;
return rr * 3 + cc;
} //根据行列求小格
void Setflag (int i, int j, int num, int f) {
r[i][num] = f;
c[j][num] = f;
block[Getblock(i, j)][num] = f;
} //为某一个元素所在行、列、小格设置上使用过或未使用的标记
bool ok (int i, int j, int num) {
return !r[i][num] && !c[j][num] && !block[Getblock(i, j)][num];
} //询问当前位置某元素是否可用
bool Dfs (int n) { //n表示现在要填的空格的编号
if (n < 0) return true;
int r = blank[n].r, c = blank[n].c;
for (int num = 1; num <= 9; ++num) {
if (ok(r, c, num)) {
board[r][c] = num;
Setflag(r, c, num, 1);
if (Dfs(n - 1)) return true;
Setflag(r, c, num, 0); //回溯
}
}
return false;
} //Based on POJ的毒瘤数据,我们选择右下向左上搜,其实左上向右下搜也可以
int main () {
int t;
cin >> t; //多组数据
while (t--) {
memset(r, 0, sizeof(r));
memset(c, 0, sizeof(c));
memset(block, 0, sizeof(block));
blank.clear(); //每组数据都要重置
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
char c;
cin >> c;
board[i][j] = c - '0'; //对付每空格的毒瘤数据
if (board[i][j]) Setflag(i, j, board[i][j], 1);
else blank.push_back(Pos(i, j));
}
}
if (Dfs(blank.size() - 1)) {
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) cout << char(board[i][j] + '0');
cout << endl;
}
}
}
return 0;
}

想想当时班里同学整日颓数独的日子,如果我做过这道题的话该是多么好的一个装逼机会啊T ^ T