23.带旋转的数独游戏

Description

数独是一个基于逻辑的组合数字放置拼图,在世界各地都很受欢迎。
在这个问题上,让我们关注 网格的拼图,其中包含 个区域。 目标是用十六进制数字填充整个网格,即 ,以便每列,每行和每个区域包含所有十六进制数字。下图显示了一个被成功解决的数独例子:

23.带旋转的数独游戏_第1张图片

昨天,周老师解决了一个数独并将其留在桌面上。 然而,龙龙想和他开个玩笑——龙龙打算对这个已经解决的数独进行多次以下操作。

选择一个 4*4 的小区域并顺时针旋转 90 度。周老师回来发现他拼好的数独板被打乱了,开始挠头,你能帮他以最小的步数恢复原样吗?请你手把手的教他怎么做,也就是需要输出方案

请注意选择要旋转的方块不能跨越任何小区域,也就是说必须选择一块完整的小区域旋转。小区域的定义在上面,16*16 的网格被分成4*4 个小区域。

Input

第一行输入一个正整数 T(1 \leq T \leq 10^3)表示数据组数;
接下来每组数据输入一个16*16 的数独图,表示被龙龙打乱后的数独面板。

Output

对于每组数据:第一行输出一个整数 ans,表示周老师最少需要逆时针旋转多少次才能恢复原样。

接下来输出ans行,每行两个数px, py,表示逆时针旋转一次第px行第px列的小矩阵

测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 以文本方式显示
  1. 1↵
  2. 681D5A0C9FDBB2F7↵
  3. 0A734B62E167D9E5↵
  4. 5C9B73EF3C208410↵
  5. F24ED18948A5CA63↵
  6. 39FAED5616400B74↵
  7. D120C4B7CA3DEF38↵
  8. 7EC829A085BE6D51↵
  9. B56438F129F79C2A↵
  10. 5C7FBC4E3D08719F↵
  11. AE8B1673BF42A58D↵
  12. 60D3AF25619C30BE↵
  13. 294190D8EA57264C↵
  14. C7D1B35606835EAB↵
  15. AF52A1E019BE4306↵
  16. 8B36DC78D425F7C9↵
  17. E409492FC7FA18D2↵
以文本方式显示
  1. 11↵
  2. 1 3↵
  3. 1 3↵
  4. 1 3↵
  5. 2 3↵
  6. 2 3↵
  7. 2 3↵
  8. 3 1↵
  9. 3 1↵
  10. 3 1↵
  11. 4 2↵
  12. 4 2↵
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

你可能感兴趣的:(程序设计与方法实践小学期,算法,数据结构)