剪枝,按照蓝书上写的,一大堆史错误,调了几天了
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int n=16;
int a[n+5][n+5],b[n+5],l[n+5],h[n+5],g[n+5][n+5],lg[10000005];
//a为数独,b为每个九宫格的状态,l为每一行的状态,h为每一列的状态,g为每个格子所在的九宫格,lg为log2
int lf[n+5][n+5],hf[n+5][n+5],bf[n+5][n+5],ln[n+5][n+5][2],hn[n+5][n+5][2],bn[n+5][n+5][2];
//lf[i][j],hf[i][j],bf[i][j]表示在第i行/i列/i宫中有多少个位置可以填j
//ln[i][j][0],ln[i][j][1],hn[i][j][0],hn[i][j][1],bn[i][j][0],bn[i][j][1]表示在第i行/i列/i宫中j的可以填的最后一个位置
//在dfs中,如果有一个位置只能填一个数,那么就填上去,然后把这个位置的行列宫的状态更新,ln,hn,bn用来记录这个位置的行列宫
inline void A(int x,int y,int t,bool f)
{
if(f)l[x]|=t;
else if((l[x]^t)<l[x])l[x]^=t;
else cout<<"error"<<endl;//调试输出错误,为了方便差错,见120行
if(f)h[y]|=t;
else if((h[y]^t)<h[y])h[y]^=t;
else cout<<"error"<<endl;
if(f)b[g[x][y]]|=t;
else if((b[g[x][y]]^t)<b[g[x][y]])b[g[x][y]]^=t;
else cout<<"error"<<endl;
}
bool f;
void dfs(int x,int y)
{
if(f)return;
//调试,输出当前状态,cph存不下就只选了x=11的情况
if(x==0&&y==0)
{
f=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<(char)(a[i][j]+'A'-1);
cout<<endl;
}
return;
}
int nx=0,ny=0,minn=114514;
vector<int>vx,vy;
vx.clear();vy.clear();
//初始化是必须的,有时候提前剪枝回溯了,但是状态没有更新
memset(lf,0,sizeof(lf));
memset(hf,0,sizeof(hf));
memset(bf,0,sizeof(bf));
//下面这三行好像没用
memset(ln,0,sizeof(ln));
memset(hn,0,sizeof(hn));
memset(bn,0,sizeof(bn));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(a[i][j])
{
//如果这个位置已经填了,那么就更新行列宫的状态
//在循环剪枝时不会return
lf[i][a[i][j]]=2;
hf[j][a[i][j]]=2;
bf[g[i][j]][a[i][j]]=2;
continue;
}
int cnt=0;
int S=l[i]&h[j]&b[g[i][j]];
if(S==0)
{
//一个数也填不了,回溯
for(int i=0;i<(int)vx.size();i++)
{
A(vx[i],vy[i],1<<a[vx[i]][vy[i]],1);
a[vx[i]][vy[i]]=0;
}
return;
}
while(S)
{
int t=S&(-S);
S-=t;
//更新行列宫的状态
cnt++;
lf[i][lg[t]]++;
hf[j][lg[t]]++;
bf[g[i][j]][lg[t]]++;
ln[i][lg[t]][0]=i;ln[i][lg[t]][1]=j;
hn[j][lg[t]][0]=i;hn[j][lg[t]][1]=j;
bn[g[i][j]][lg[t]][0]=i;bn[g[i][j]][lg[t]][1]=j;
}
if(i==x&&j==y)continue;//跳过
//只能填一个数,立刻填上去
if(cnt==1){
int t=l[i]&h[j]&b[g[i][j]];
A(i,j,t,0);
a[i][j]=lg[t];
vx.push_back(i);
vy.push_back(j);
}
else if(cnt<minn)
{
minn=cnt;
nx=i;
ny=j;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
//这里没有一个可以填的位置,那么就回溯
if(lf[i][j]==0||hf[i][j]==0||bf[i][j]==0)
{
lf[i][j]=hf[i][j]=bf[i][j]=0;
for(int i=0;i<(int)vx.size();i++)
{
A(vx[i],vy[i],1<<a[vx[i]][vy[i]],1);
a[vx[i]][vy[i]]=0;
}
return;
}
//下面这段去掉会超时,加上会出现error
// if(lf[i][j]==1&&a[ln[i][j][0]][ln[i][j][1]]==0)
// {
// a[ln[i][j][0]][ln[i][j][1]]=j;
// A(ln[i][j][0],ln[i][j][1],1<<j,0);
// vx.push_back(ln[i][j][0]);
// vy.push_back(ln[i][j][1]);
// }
// if(hf[i][j]==1&&a[hn[i][j][0]][hn[i][j][1]]==0)
// {
// a[hn[i][j][0]][hn[i][j][1]]=j;
// A(hn[i][j][0],hn[i][j][1],1<<j,0);
// vx.push_back(hn[i][j][0]);
// vy.push_back(hn[i][j][1]);
// }
// if(bf[i][j]==1&&a[bn[i][j][0]][bn[i][j][1]]==0)
// {
// a[bn[i][j][0]][bn[i][j][1]]=j;
// A(bn[i][j][0],bn[i][j][1],1<<j,0);
// vx.push_back(bn[i][j][0]);
// vy.push_back(bn[i][j][1]);
// }
}
}
int S=l[x]&h[y]&b[g[x][y]];
while(S)
{
int t=S&(-S);
S^=t;
a[x][y]=lg[t];
A(x,y,t,0);
dfs(nx,ny);
A(x,y,t,1);
a[x][y]=0;
}
for(int i=0;i<(int)vx.size();i++)
{
A(vx[i],vy[i],1<<a[vx[i]][vy[i]],1);
a[vx[i]][vy[i]]=0;
}
return;
}
signed main()
{
cin.tie(0)->sync_with_stdio(0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
g[i][j]=(i-1)/4*4+(j-1)/4+1;
for(int i=1;i<=n;i++)lg[1<<i]=i;
// string s;
int T;cin>>T;
while(T--)
{
// if(s=="end")break;
for(int i=1;i<=n;i++)
{
b[i]=l[i]=h[i]=0;
for(int j=1;j<=n;j++)
{
b[i]|=1<<j;
l[i]|=1<<j;
h[i]|=1<<j;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
char c;cin>>c;
if(c=='-')a[i][j]=0;
else a[i][j]=c-'A'+1;
if(a[i][j])
{
l[i]^=1<<a[i][j];
h[j]^=1<<a[i][j];
b[g[i][j]]^=1<<a[i][j];
}
}
f=0;
dfs(1,1);
//中间输出不出来,只能输出最后的结果看看有没有回溯完
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(a[i][j])cout<<(char)(a[i][j]+'A'-1);
else cout<<'-';
cout<<endl;
}
// cout<<"end";
}
return 0;
}