链接:
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;
}