题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6341
题意:给你16*16的数独,分为16个4*4的小块,现在有某些块被逆时针旋转了多次,现在要你用最少旋转次数把数独还原好。
题解:dfs,每块最多旋转3次,那么我们就直接暴力搜就好了。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
char op[20][20],ma[10][10];
int ans;
bool vis[20];
void roat(int x,int y) ///旋转90
{
for(int i=1,a=y;i<=4;i++,a++)
for(int j=1,b=x;j<=4;j++,b--)
ma[i][j]=op[b][a];
for(int i=4,a=x;i>=1;i--,a--)
for(int j=1,b=y;j<=4;j++,b++)
op[a][b]=ma[i][j];
}
int F(char x){
if(x>='0'&&x<='9') return x-'0';
else return x-'A'+10;
}
bool check(int k) ///判断前k行是否满足
{
for(int i=k-3;i<=k;i++){
memset(vis,0,sizeof(vis));
for(int j=1;j<=16;j++){
if(vis[F(op[i][j])]) return 0;
vis[F(op[i][j])]=1;
}
}
for(int j=1;j<=16;j++)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=k;i++){
if(vis[F(op[i][j])]) return 0;
vis[F(op[i][j])]=1;
}
}
return 1;
}
void dfs(int k,int num) ///枚举前k行的数独
{
if(num>ans) return;
if(k==20) {
ans=min(ans,num);return;
}
for(int i=0;i<4;i++,roat(k,1))
for(int j=0;j<4;j++,roat(k,5))
for(int x=0;x<4;x++,roat(k,9))
for(int y=0;y<4;y++,roat(k,13))
{
if(!check(k)) continue;
dfs(k+4,num+i+j+x+y);
}
return;
}
int main()
{
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
for(int i=1;i<=16;i++)
scanf("%s",op[i]+1);
ans=64; ///有16块,每块最多旋转3次
dfs(4,0);
printf("%d\n",ans);
}
return 0;
}