標準 9×9 數獨,輸入多組測資,0 代表空格。輸出任一合法解。限制:每行、每列、每 3×3 宮內數字 1~9 不重複。
用三個陣列記錄行、列、宮的已用數字狀態,以 int 位元操作 (1 << d) 實現 O(1) 合法性檢查與狀態更新,極大提升速度。
row[9]:第 i 行已用數字位元遮罩。col[9]:第 j 列已用數字位元遮罩。box[9]:第 k 宮已用數字位元遮罩,k = (i/3)*3 + j/3。empties。solved 並層層返回。#include <bits/stdc++.h> using namespace std; char board[9][10]; // +1 for null terminator int rowMask[9], colMask[9], boxMask[9]; vector> empties; bool solved; inline int boxIndex(int r, int c) { return (r/3)*3 + c/3; } void dfs(int idx) { if (solved) return; if (idx == (int)empties.size()) { solved = true; return; } int r = empties[idx].first; int c = empties[idx].second; int b = boxIndex(r, c); int used = rowMask[r] | colMask[c] | boxMask[b]; // 嘗試數字 1~9 (bit 1~9) for (int d = 1; d <= 9; ++d) { int bit = 1 << d; if (used & bit) continue; // 放置 board[r][c] = '0' + d; rowMask[r] |= bit; colMask[c] |= bit; boxMask[b] |= bit; dfs(idx + 1); if (solved) return; // 回溯 rowMask[r] &= ~bit; colMask[c] &= ~bit; boxMask[b] &= ~bit; board[r][c] = '0'; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; if (!(cin >> T)) return 0; while (T--) { // 初始化 memset(rowMask, 0, sizeof(rowMask)); memset(colMask, 0, sizeof(colMask)); memset(boxMask, 0, sizeof(boxMask)); empties.clear(); solved = false; for (int i = 0; i < 9; ++i) { cin >> board[i]; for (int j = 0; j < 9; ++j) { if (board[i][j] == '0') { empties.emplace_back(i, j); } else { int d = board[i][j] - '0'; int bit = 1 << d; rowMask[i] |= bit; colMask[j] |= bit; boxMask[boxIndex(i, j)] |= bit; } } } dfs(0); for (int i = 0; i < 9; ++i) cout << board[i] << '\n'; if (T) cout << '\n'; // 依題目格式決定是否空行 } return 0; }
used = row|col|box 一次取得所有衝突位,if (used & bit) 判斷衝突,比陣列 bool used[10] 快數倍。sort(empties.begin(), empties.end(), [](...){ return __builtin_popcount(rowMask[r]|colMask[c]|boxMask[b]); }); 可進一步剪枝,但 9×9 規模下線性序通常足夠。solved 剪枝:找到第一解即停止所有遞迴。若需確認解唯一,找到第一解後繼續搜尋,若再找到第二解則非唯一。修改 dfs 回傳 int 計數即可。