#include <iostream>
#include <cstring>
using namespace std;
const int N=16;
int mp[21][21]={0};
int row[21],col[21],matrix[21];
int ccnt[21]={0};
bool isok=false;
void printMap()
{
cout<<"------------------------------\n";
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(mp[i][j]==-1) printf("-");
else printf("%c",char(mp[i][j]+'A'));
}
cout<<"\n";
}
cout<<"------------------------------\n";
}
int getCnt(int i,int j)
{
int tot=0;
for(int k=0;k<16;k++)
if((row[i]>>k)&1||(col[j]>>k)&1||(matrix[i/4*4+j/4]>>k)&1) tot++;
return tot;
}
void Put(int i,int j,int k)
{
mp[i][j]=k;
row[i]|=(1<<mp[i][j]),col[j]|=(1<<mp[i][j]),matrix[i/4*4+j/4]|=(1<<mp[i][j]);
}
void Take(int i,int j,int k)
{
mp[i][j]=-1;
row[i]&=(~(1<<k)),col[j]&=(~(1<<k)),matrix[i/4*4+j/4]&=(~(1<<k));
}
void dfs(int tot)
{
printMap();
if(tot>256) isok=true,printMap();
if(isok) return;
int x=-1,y=-1,minn=0x7fffffff;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
if(mp[i][j]!=-1) continue;
int k=16-getCnt(i,j);
if(k==1)//剪枝1,只能放一个
{
for(int l=0;l<16;l++)
if(!((row[i]>>l)&1||(col[j]>>l)&1||(matrix[i/4*4+j/4]>>l)&1))
{
ccnt[l]++;
Put(i,j,l);
dfs(tot+1);
Take(i,j,l);
ccnt[l]--;
break;
}
return;
}
if(k==0) return;
if(k<minn) minn=k,x=i,y=j;
}
for(int c=0;c<16;c++)//剪枝2,有一个字母还要放的个数小于能放的格子数
{
int t=0;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
if(!((row[i]>>c)&1||((col[j]>>c)&1)||((matrix[i/4*4+j/4]>>c)&1))&&mp[i][j]==-1) t++;
if(t<16-ccnt[c]) return;
}
for(int i=0;i<16;i++)
{
if(!((row[x]>>i)&1||(col[y]>>i)&1||(matrix[x/4*4+y/4]>>i)&1))
{
ccnt[i]++;
Put(x,y,i);
dfs(tot+1);
Take(x,y,i);
ccnt[i]--;
}
}
}
int main()
{
memset(mp,-1,sizeof(mp));
int cnt=0;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
char c;
cin>>c;
if(c!='-')
{
Put(i,j,c-'A');
cnt++;
ccnt[c-'A']++;
}
}
dfs(cnt);
return 0;
}
我看了一下别人的题解,但好像他们说的行、列、十六宫格剪枝我都在剪枝1中出现了。