直接暴力搜+可行性剪枝。具体看代码,注意:顺时针旋转
#include<bits/stdc++.h>
using namespace std;
int vis[20];
char s[20][20];
int a[20][20],b[20][20];
int ans;
void ro(int x,int y)
{
for(int i=x;i<x+4;i++)
{
for(int j=y;j<y+4;j++)
{
b[i][j]=a[i][j];
}
}
for(int i=x,ii=y;i<x+4,ii<y+4;i++,ii++)
for(int j=y,jj=x+3;j<y+4,jj>=x;j++,jj--)
a[i][j]=b[jj][ii];
}
int judge(int x)
{
for(int i=x-3;i<=x;i++)//每行数的和要等于120
{
int sum=0;
for(int j=1;j<=16;j++)sum+=a[i][j];
if(sum!=120)return 0;
}
for(int i=x-3;i<=x;i++)//每行不能有重复出现的数
{
memset(vis,0,sizeof vis);
for(int j=1;j<=16;j++)
{
if(vis[a[i][j]])return 0;
vis[a[i][j]]=1;
}
}
for(int j=1;j<=16;j++)//每列不能有重复出现的数
{
memset(vis,0,sizeof vis);
for(int i=1;i<=x;i++)
{
if(vis[a[i][j]])return 0;
vis[a[i][j]]=1;
}
}
return 1;
}
void dfs(int k,int num)
{
if(k==20)
{
ans=min(num,ans);
return ;
}
for(int aa=0;aa<4;aa++,ro(k-3,1))
for(int bb=0;bb<4;bb++,ro(k-3,5))
for(int c=0;c<4;c++,ro(k-3,9))
for(int d=0;d<4;d++,ro(k-3,13))
{
if(judge(k)==0) continue;
dfs(k+4,num+aa+bb+c+d);
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
for(int i=1;i<=16;i++) scanf("%s",s[i]+1);
for(int i=1;i<=16;i++)
for(int j=1;j<=16;j++)
{
if(s[i][j]<='9')
a[i][j]=s[i][j]-'0';
else
a[i][j]=s[i][j]-'A'+10;
}
ans=16*4;
dfs(4,0);
cout<<ans<<endl;
}
return t;
}