題目鏈接:點擊這裏
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 9, M = 1 << N;
int ones[M], map[M];
int row[N], col[N], cell[3][3];
char str[100];
// is_set爲true表示在(x,y)位置填上數t,false表示在(x,y)位置刪掉數t
void draw(int x, int y, int t, bool is_set)
{
if(is_set) str[x * N + y] = '1' + t;
else str[x * N + y] = '.';
int v = 1 << t;
if(!is_set) v = -v;
row[x] -= v;
col[y] -= v;
cell[x / 3][y / 3] -= v;
}
int lowbit(int x)
{
return x & -x;
}
int get(int x, int y) // 求當前格子都能填哪些數,即row & col & cell
{
return row[x] & col[y] & cell[x / 3][y / 3];
}
bool dfs(int cnt)
{
if(!cnt) return true;
// 優化搜索順序:找到分支數最少的一個空格
int minv = 10;
int x, y;
for(int i = 0; i < N; i ++ )
{
for(int j = 0; j < N; j ++ )
{
if(str[i * N + j] == '.')
{
int state = get(i, j);
if(ones[state] < minv)
{
minv = ones[state];
x = i, y = j;
}
}
}
}
int state = get(x, y);
for(int i = state; i; i -= lowbit(i)) // 枚舉所有的1
{
int t = map[lowbit(i)];
draw(x, y, t, true);
if(dfs(cnt - 1)) return true;
draw(x, y, t, false); // 恢復現場
}
return false;
}
int main()
{
/* 打表 */
for(int i = 0; i < N; i ++ ) // lowbit返回2的多少次冪,而map記錄對2取對數的結果
map[1 << i] = i;
for(int i = 0; i < 1 << N; i ++ ) // ones存儲每個二進制狀態中有多少個1
for(int j = 0; j < N; j ++ )
ones[i] += i >> j & 1;
while(cin >> str, str[0] != 'e')
{
/* 初始化 */
for(int i = 0; i < N; i ++ ) // 每行、每列初始狀態都爲111111111
row[i] = col[i] = (1 << N) - 1;
for(int i = 0; i < 3; i ++ ) // 每個九宮格初始狀態都爲111111111
for(int j = 0; j < 3; j ++ )
cell[i][j] = (1 << N) - 1;
int cnt = 0;
for(int i = 0, k = 0; i < N; i ++ )
{
for(int j = 0; j < N; j ++, k ++ )
{
if(str[k] != '.') // 把初始數字填到對應的格中,改變相應row、col、cell的狀態
{
int t = str[k] - '1';
draw(i, j, t, true);
}
else cnt ++ ;
}
}
dfs(cnt);
puts(str);
}
return 0;
}