数独是一个基于逻辑的组合数字放置拼图,在世界各地都很受欢迎。
在这个问题上,让我们关注 网格的拼图,其中包含 个区域。 目标是用十六进制数字填充整个网格,即 ,以便每列,每行和每个区域包含所有十六进制数字。下图显示了一个被成功解决的数独例子:
昨天,周老师解决了一个数独并将其留在桌面上。 然而,龙龙想和他开个玩笑——龙龙打算对这个已经解决的数独进行多次以下操作。
选择一个 4*4 的小区域并顺时针旋转 90 度。周老师回来发现他拼好的数独板被打乱了,开始挠头,你能帮他以最小的步数恢复原样吗?请你手把手的教他怎么做,也就是需要输出方案。
请注意选择要旋转的方块不能跨越任何小区域,也就是说必须选择一块完整的小区域旋转。小区域的定义在上面,16*16 的网格被分成4*4 个小区域。
第一行输入一个正整数 表示数据组数;
接下来每组数据输入一个16*16 的数独图,表示被龙龙打乱后的数独面板。
对于每组数据:第一行输出一个整数 ans,表示周老师最少需要逆时针旋转多少次才能恢复原样。
接下来输出ans行,每行两个数px, py,表示逆时针旋转一次第px行第px列的小矩阵
测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
---|---|---|---|---|---|
测试用例 1 | 以文本方式显示
|
以文本方式显示
|
1秒 | 153600KB | 0 |
这道题用的DFS,本质和之前的解谜游戏相同。
为了方便旋转,我用四维数组来储存数组。sd[i][j][n][m],表示第(i,j)个小区域,某个数字坐标(n,m)。将输入转化成0-15存储。
记得初始化
定义了一个逆时针旋转函数,并使用count来记录旋转次数0-3.每个格子先旋转三次,记录次数。然后再转一次,表示还原,且count记录为0。每当i==3,检验该行格子是否满足,应该只需检验里面的一行就可以了;如果不满足,就结束,可以减少运算量否则16^4还是很多的。当i==4时,说明所有操作结束,再检查列就可以了。
如果可以,更新最优结果和最优方案。
#include
#include
#define max 65536+1
int sd[4][4][4][4],count[4][4],ulti[4][4],ans=max;
//第(i,j)个区域,内部坐标(n,m),旋转次数count[i][j];
void init()
{
memset(count,0,sizeof(count));
memset(ulti,0,sizeof(count));
ans=max;
}
void input()
{
//第(i,j)个区域,坐标(n,m);
int i,j,n,m;
char temp;
for(i=0;i<4;i++){
for(n=0;n<4;n++){
for(j=0;j<4;j++){
for(m=0;m<4;m++){
temp=getchar();
if(temp>='0' && temp<='9') sd[i][j][n][m]=temp-'0';
else sd[i][j][n][m]=temp-'A'+10;
}
}
getchar();
}
}
}
void out()
{
printf("%d\n",ans);
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
while(ulti[i][j]--)
printf("%d %d\n",i+1,j+1);
}
}
}
//检验第i大行是否正确
int row(int i)
{
int k[16]={0},j,n,m;
for(n=0;n<3;n++){
memset(k,0,sizeof(k));
for(j=0;j<4;j++){
for(m=0;m<4;m++){
if(k[sd[i][j][n][m]]>0) return 0;
else k[sd[i][j][n][m]]++;
}
}
}
return 1;
}
//检验是否复原
int isOK()
{
int i,j,n,m,k[16];
for(j=0;j<4;j++){
for(m=0;m<3;m++){
memset(k,0,sizeof(k));
for(i=0;i<4;i++){
for(n=0;n<4;n++){
if(k[sd[i][j][n][m]]>0) return 0;
else k[sd[i][j][n][m]]++;
}
}
}
}
return 1;
}
//更新记录
void renew(int step)
{
ans=step;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
ulti[i][j]=count[i][j];
}
//数独测试输出
void testput()
{
int i,j,n,m;
for(i=0;i<4;i++){
for(n=0;n<4;n++){
for(j=0;j<4;j++){
for(m=0;m<4;m++){
printf("%3d",sd[i][j][n][m]);
}
printf("\t");
}
printf("\n");
}
printf("\n");
}
}
//旋转第(i,j)区域
void spin(int i,int j)
{
int m,n,temp[4][4];
for(n=0;n<4;n++){
for(m=0;m<4;m++){
temp[3-m][n]=sd[i][j][n][m];
}
}
for(n=0;n<4;n++){
for(m=0;m<4;m++){
sd[i][j][n][m]=temp[n][m];
}
}
count[i][j]++;
}
//撤销旋转第(i,j)区域
void undo(int i,int j)
{
int m,n,temp[4][4];
for(n=0;n<4;n++){
for(m=0;m<4;m++){
temp[m][3-n]=sd[i][j][n][m];
}
}
for(n=0;n<4;n++){
for(m=0;m<4;m++){
sd[i][j][n][m]=temp[n][m];
}
}
count[i][j]--;
}
void dfs(int i,int j,int step)
{
if(i==4){
if(isOK() && step