题目:有一个4*4*4*4的数独,每一横每一竖每一个小方块中都无重复的字母,即都为0-9,A-F.。有一个已经填好的数独,若干个4*4的方块被逆时针拧转了若干次,问拧转回来至少需要多少次。
思路:dfs,看起来复杂度会很大,但是数独的限制性较大,加个最优化剪枝和可行性剪枝(判断转到每一4*4的区域后是不是与前面的转好了的冲突)能减掉很多的可能性。
#include <bits/stdc++.h>
using namespace std;
int t,a[22][22];
int tmp[22][22]={0};
void rotat(int x,int y)
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
tmp[j][4-i+1]=a[(x-1)*4+i][(y-1)*4+j];
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
a[(x-1)*4+i][(y-1)*4+j]=tmp[i][j];
}
int book[22];
bool check(int x,int y)
{
for(int i=x*4-3;i<=x*4;i++)
{
memset(book,0,sizeof book);
for(int j=1;j<=y*4;j++)
{
if(!book[a[i][j]])
book[a[i][j]]=1;
else
return 0;
}
}
for(int j=y*4-3;j<=y*4;j++)
{
memset(book,0,sizeof book);
for(int i=1;i<=x*4;i++)
{
if(!book[a[i][j]])
book[a[i][j]]=1;
else
return 0;
}
}
return 1;
}
int ans;
void dfs(int x,int y,int sum)
{
if(sum>=ans) return;
if(x==5)
{
ans=sum;
return ;
}
int xx=x,yy=y+1;
if(yy==5) {yy=1;xx++;}
for(int i=0;i<4;i++)
{
if(i) rotat(x,y);
if(check(x,y))
dfs(xx,yy,sum+i);
}
rotat(x,y);
}
char s[22];
int main()
{
scanf("%d",&t);
while(t--)
{
for(int i=1;i<=16;i++)
{
scanf("%s",s+1);
for(int j=1;j<=16;j++)
{
if(s[j]>'9')
a[i][j]=s[j]-'A'+10;
else a[i][j]=s[j]-'0';
}
}
ans=55;
/*
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
printf("%2d ",a[4+i][2*4+j]);
puts("");
}
puts("****************");
rotat(2,3);
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
printf("%2d ",a[4+i][2*4+j]);
puts("");
}
*/
dfs(1,1,0);
printf("%d\n",ans);
}
return 0;
}