解题技巧:1.数独每个格子记录自身还能填的数字,每次寻找能填数字数最少的格子填充数字。
2.使用“禁用计数”的方式,记录每个格子某个数字被禁用的次数,以便脱离禁用后恢复可填性。
#include <cstdio> #include <cstring> #include <set> #include <vector> using std::set; using std::vector; struct Elem { int num; set<int> lefts; }; set<int> LEFTS; const int maxn = 9; char charMap[maxn][maxn+1]; Elem Map[maxn][maxn]; int ans[maxn][maxn]; int count; int f[maxn][maxn][maxn + 1]; struct Cor { int r, c; Cor(int r_ = 0, int c_ = 0) : r(r_), c(c_) {} bool operator<(const Cor &cor) const { return (r < cor.r) || (r == cor.r && c < cor.c); } }; set<Cor> unfills; void init() { for (int i = 0; i < maxn; ++i) { for (int j = 0; j < maxn; ++j) { Map[i][j].num = 0; Map[i][j].lefts.insert(LEFTS.begin(), LEFTS.end()); } } for (int i = 0; i < maxn; ++i) { for (int j = 0; j < maxn; ++j) { for (int k = 0; k < maxn; ++k) { f[i][j][k + 1] = 0; } } } count = 0; unfills.clear(); } void input() { for (int i = 0; i < maxn; ++i) { scanf("%s", charMap[i]); } } void transform() { for (int i = 0; i < maxn; ++i) { for (int j = 0; charMap[i][j] != ‘\0‘; ++j) { if (charMap[i][j] != ‘_‘) { Map[i][j].num = charMap[i][j] - ‘0‘; } else { unfills.insert(Cor(i, j)); } } } } void setting(int r, int c, int num) { Map[r][c].num = num; for (int i = 0; i < maxn; ++i) { Map[r][i].lefts.erase(num); ++f[r][i][num]; Map[i][c].lefts.erase(num); ++f[i][c][num]; } int beginr = r / 3 * 3; int beginc = c / 3 * 3; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { Map[i + beginr][j + beginc].lefts.erase(num); ++f[i + beginr][j + beginc][num]; } } } void resume(int r, int c, int num) { Map[r][c].num = 0; for (int i = 0; i < maxn; ++i) { if (--f[r][i][num] == 0) Map[r][i].lefts.insert(num); if (--f[i][c][num] == 0) Map[i][c].lefts.insert(num); } int beginr = r / 3 * 3; int beginc = c / 3 * 3; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (--f[i+beginr][j+beginc][num] == 0) Map[i + beginr][j + beginc].lefts.insert(num); } } } void predeal() { for (int i = 0; i < maxn; ++i) { for (int j = 0; j < maxn; ++j) { if (Map[i][j].num != 0) { setting(i, j, Map[i][j].num); } } } } void dfs() { if (unfills.empty()) { // 达到一种目的状态 ++count; if (count > 1) return; for (int i = 0; i < maxn; ++i) { for (int j = 0; j < maxn; ++j) { ans[i][j] = Map[i][j].num; } } } else { // 遍历unfills,寻找最小的 set<Cor>::iterator iter = unfills.begin(), target = unfills.begin(); while (iter != unfills.end()) { const Cor &cor1 = *iter; const Cor &cor2 = *target; if (Map[cor1.r][cor1.c].lefts.size() < Map[cor2.r][cor2.c].lefts.size()) { target = iter; } ++iter; } Cor cor = *target; unfills.erase(target); set<int> _lefts(Map[cor.r][cor.c].lefts); // set<int>::iterator iter1 = _lefts.begin(); while (iter1 != _lefts.end()) { int num = *iter1; setting(cor.r, cor.c, num); dfs(); resume(cor.r, cor.c, num); ++iter1; } unfills.insert(cor); } } int main() { for (int i = 1; i <= 9; ++i) LEFTS.insert(i); int t; scanf("%d", &t); for (int tt = 1; tt <= t; ++tt) { // 初始化 init(); // 输入 input(); // 转化 transform(); // 预处理 predeal(); // 深搜 dfs(); if (count == 0) { printf("Puzzle %d has no solution\n", tt); } else if (count == 1) { printf("Puzzle %d solution is\n", tt); for (int i = 0; i < maxn; ++i) { for (int j = 0; j < maxn; ++j) { printf("%d", ans[i][j]); } printf("\n"); } } else if (count > 1) { printf("Puzzle %d has %d solutions\n", tt, count); } if (tt != t) printf("\n"); } return 0; }
时间: 2024-10-05 10:19:28