题意就是给你一个已经解完的数独,但是他的某几块被逆时针旋转过几次,问你最小的旋转次数。
当时比赛的时候,因为被题面吓到了,以为是难题,就没有仔细思考,现在看看,就是一道搜索题,用bfs和dfs都可以过。
一开始想着如果用bfs的话,可能还要存下每旋转一次的状态,会显得很繁琐,就没有选择bfs,用了dfs。
自己写了一个dfs,可能是因为当时有点困,写起来小错误很多,写完debug了很久。虽然出了答案,但样例都会超时,然后想着可能是剪枝没剪好,就加了各种各样的剪枝,交上去还是T了。没办法,去网上学习一下大佬的做法,然后自己重新敲了一遍,因为之前已经写过一遍了,这次就很顺,写完稍微debug一下就出样例了。交上去就过了。680ms
同时,我也发现我原先那个代码的问题了,我旋转矩阵的方法太繁琐了,估计只要换一种旋转方法就可以过了。
(PS:听说有大佬可以剪到15ms,但是没找到,真的是震惊了。)
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=20;
int arr[maxn][maxn];
int fl[maxn]={0};
int T;
int Min;
bool pd(int num)
{
for(int i=1;i<=num;i++)
{
memset(fl,0,sizeof fl);
for(int j=1;j<=16;j++)
{
if(fl[arr[j][i]]==0)
fl[arr[j][i]]=1;
else return false;
}
}
for(int i=1;i<=16;i++)
{
memset(fl,0,sizeof fl);
for(int j=1;j<=num;j++)
{
if(fl[arr[i][j]]==0)
fl[arr[i][j]]=1;
else return false;
}
}
return true;
}
void xz(int num,int num1)
{
int arr1[5][5]={0};
int a=num1;
int b=num;
for(int i=1,a=num1;i<=4;i++,a++)
{
for(int j=1,b=num;j<=4;j++,b++)
{
arr1[i][j]=arr[a][b];
}
}
for(int i=1,a=num1;i<=4;i++)
{
for(int j=1,b=num;j<=4;j++)
{
arr[5-j+a-1][b+i-1]=arr1[i][j];
}
}
}
void dfs(int num,int val)
{
if(val>Min)return;
if(num==17)
{
Min=min(Min,val);
return;
}
for(int i=1;i<=4;i++,xz(num,1))
{
for(int j=1;j<=4;j++,xz(num,5))
{
for(int m=1;m<=4;m++,xz(num,9))
{
for(int n=1;n<=4;n++,xz(num,13))
{
if(pd(num+3))
{
dfs(num+4,val+i+j+m+n-4);
}
}
}
}
}
}
int main()
{
cin>>T;
while(T--)
{
Min=1000;
memset(arr,-1,sizeof arr);
for(int i=1;i<=16;i++)
{
char ch[maxn];
scanf("%s",ch+1);
for(int j=1;j<=16;j++)
{
if(ch[j]>='0'&&ch[j]<='9')
{
arr[j][i]=ch[j]-'0';
}
else
{
arr[j][i]=ch[j]-'A'+10;
}
}
}
dfs(1,0);
cout<<Min<<endl;
}
}