链接:
https://www.acwing.com/problem/content/171/
题意:
请你将一个16x16的数独填写完整,使得每行、每列、每个4x4十六宫格内字母A~P均恰好出现一次。
保证每个输入只有唯一解决方案。
思路:
每个坐标维护一个16位的数, 用来记录某个值是否使用.
对每个位置, 如果只能填一个,则直接填, 对空格如果不能填, 则返回.
对每一行, 只能在一个位置使用的值直接填, 同时一行不能覆盖a-p,则返回,
列, 块同理.
再从所有可行位置,找到一个可填值最少的开始枚举.
还要多开数组记录状态, 方便复原.
代码:
#include <bits/stdc++.h> using namespace std; const int N = 16; char Map[N][N+1]; char TmpMap[N*N+1][N][N+1]; int State[N][N]; int TmpS1[N*N+1][N][N], TmpS2[N*N+1][N][N]; int Num[1<<N], Cnt[1<<N]; int cnt; int Lowbit(int x) { return x&(-x); } void Change(int x, int y, int p) { Map[x][y] = 'A'+p; for (int i = 0;i < N;i++) { State[x][i] &= ~(1<<p); State[i][y] &= ~(1<<p); } int sx = (x/4)*4, sy = (y/4)*4; for (int i = 0;i < 4;i++) { for (int j = 0;j < 4;j++) State[sx+i][sy+j] &= ~(1<<p); } State[x][y] = 1<<p; } bool Dfs(int step) { if (step == 0) return true; int tmpcnt = step; memcpy(TmpS1[tmpcnt], State, sizeof State); memcpy(TmpMap[tmpcnt], Map, sizeof Map); //保存副本 //处理每个空格 for (int i = 0;i < N;i++) { for (int j = 0;j < N;j++) { if (Map[i][j] == '-') { if (State[i][j] == 0) { memcpy(State, TmpS1[tmpcnt], sizeof State); memcpy(Map, TmpMap[tmpcnt], sizeof Map); return false; } if (Cnt[State[i][j]] == 1) { Change(i, j, Num[State[i][j]]); step--; } } } } //处理每一行 for (int i = 0;i < N;i++) { int all = 0, use = (1<<N)-1; int used = 0; for (int j = 0;j < N;j++) { int s = State[i][j]; use &= ~(all & s);//记录只在一个位置出现过的点 all |= s;//记录全集 if (Map[i][j] != '-') used |= State[i][j];//记录放置的点 } if (all != (1<<N)-1) { memcpy(State, TmpS1[tmpcnt], sizeof State); memcpy(Map, TmpMap[tmpcnt], sizeof Map); return false; } for (int j = use;j > 0;j -= Lowbit(j)) { int t = Lowbit(j); if (!(used & t)) { for (int k = 0;k < N;k++) { if (State[i][k] & t) { Change(i, k, Num[t]); --step; break; } } } } } //处理每一列 for (int i = 0;i < N;i++) { int all = 0, use = (1<<N)-1; int used = 0; for (int j = 0;j < N;j++) { int s = State[j][i]; use &= ~(all & s); all |= s; if (Map[j][i] != '-') used |= State[j][i]; } if (all != (1<<N)-1) { memcpy(State, TmpS1[tmpcnt], sizeof State); memcpy(Map, TmpMap[tmpcnt], sizeof Map); return false; } for (int j = use;j > 0;j -= Lowbit(j)) { int t = Lowbit(j); if (!(used & t)) { for (int k = 0;k < N;k++) { if (State[k][i] & t) { Change(k, i, Num[t]); --step; break; } } } } } //处理每一个区块 for (int i = 0;i < N;i++) { int all = 0, use = (1<<N)-1; int used = 0; for (int j = 0;j < N;j++) { int sx = i/4*4, sy = i%4*4; int dx = j/4, dy = j%4; int s = State[sx+dx][sy+dy]; use &= ~(all & s); all |= s; if (Map[sx+dx][sy+dy] != '-') used |= State[sx+dx][sy+dy]; } if (all != (1<<N)-1) { memcpy(State, TmpS1[tmpcnt], sizeof State); memcpy(Map, TmpMap[tmpcnt], sizeof Map); return false; } for (int j = use;j > 0;j -= Lowbit(j)) { int t = Lowbit(j); if (!(used & t)) { for (int k = 0;k < N;k++) { int sx = i/4*4, sy = i%4*4; int dx = k/4, dy = k%4; if (State[sx+dx][sy+dy] & t) { Change(sx+dx, sy+dy, Num[t]); --step; break; } } } } } // cout << step << endl; if (step == 0) return true; int x, y, s = 100; for (int i = 0;i < N;i++) { for (int j = 0;j < N;j++) { if (Map[i][j] == '-' && Cnt[State[i][j]] < s) { s = Cnt[State[i][j]]; x = i, y = j; } } } memcpy(TmpS2[tmpcnt], State, sizeof State); for (int i = State[x][y];i > 0;i -= Lowbit(i)) { memcpy(State, TmpS2[tmpcnt], sizeof State); Change(x, y, Num[Lowbit(i)]); if (Dfs(step-1)) return true; } memcpy(State, TmpS1[tmpcnt], sizeof State); memcpy(Map, TmpMap[tmpcnt], sizeof Map); return false; } int main() { for (int i = 0;i < N;i++) Num[1<<i] = i; for (int i = 0;i < (1<<N);i++) { for (int j = i;j > 0;j -= Lowbit(j)) Cnt[i]++; } while (cin >> Map[0]) { for (int i = 1;i < N;i++) cin >> Map[i]; for (int i = 0;i < N;i++) { for (int j = 0;j < N;j++) State[i][j] = (1<<N)-1; } cnt = 0; for (int i = 0;i < N;i++) { for (int j = 0;j < N;j++) { if (Map[i][j] != '-') Change(i, j, Map[i][j]-'A'); else cnt++; } } Dfs(cnt); for (int i = 0;i < N;i++) puts(Map[i]); puts(""); } return 0; }