数独是一个基于逻辑的组合数字放置拼图,在世界各地都很受欢迎。 在这个问题上,让我们关注 16 * 16 网格的拼图,其中包含 4 * 4 个区域。 目标是用十六进制数字填充整个网格,即 0123456789 A B C D E F,以便每列,每行和每个区域包含所有十六进制数字。 下图显示了一个被成功解决的数独例子:
昨天,周老师解决了一个数独并将其留在桌面上。 然而,龙龙想和他开个玩笑——龙龙打算对这个已经解决的数独进行多次以下操作。 选择一个 4 *4 的小区域并顺时针旋转 90 度。 周老师回来发现他拼好的数独板被打乱了,开始挠头,你能帮他以最小的步数恢复原样吗?请你手把手的教他怎么做,也就是需要输出方案。 请注意选择要旋转的方块不能跨越任何小区域,也就是说必须选择一块完整的小区域旋转。小区域的定义在上面,16 * 16 的网格被分成 4 * 4 个小区域。 Input 第一行输入一个正整数 T 空格 左括号 1 小於等於 T 小於等於 10 立方 右括号 表示数据组数; 接下来每组数据输入一个 16 * 16 的数独图,表示被龙龙打乱后的数独面板。 Output 对于每组数据: 第一行输出一个整数 a n s ,表示周老师最少需要逆时针旋转多少次才能恢复原样。 接下来输出 a n s 行,每行两个数pxpy,表示逆时针旋转一次第px行第py列的小矩阵。
解题思路:
本题爆搜时间复杂度较高,需要进行大量剪枝才行。
我们先写好需要用的函数,之后方便调用
- 获得值函数(将a~e转换为10~15,方便存储)
- 旋转函数
- 检查函数(每次检查刚放进来的块,如果满足数独性质,则返回1,并且将块中元素加入检查函数的检查队列中,用于下一次放块后的检查)
- 回溯函数(若之后放块都不能满足要求,说明这个块放在这里是错的,我们就要将检查函数的检查队列中这个块的数据删除,便于下一次能正确检查)
- dfs从左到右从上到下dfs
- 记录数据
- 回溯数据
经巨佬提醒我们发现旋转函数的复杂度还是高,我们可以预处理每一个小块旋转后的样子,这样的话还可以减少时间//不过不需要这个也行
代码:
#include<bits/stdc++.h>
using namespace std;
int a[30][30];
int ck1[22][22];
int ck2[22][22];
struct Node
{
int x, y, t;
};
int ans;
vector<Node> as, fas;
int get(char ch){
if (ch == '0')return 10;
else if (ch > '0' && ch <= '9')return ch - '0';
else return ch - 'A' + 11;
}
void roat(int x ,int y ){
int xx=(x)*4; //块之间的映射1~4 --> 1~16
int yy=(y)*4;
int g[5][5];
for(int i=xx;i<=xx+3;i++){
for(int j=yy;j<=yy+3;j++){
g[i-xx][j-yy]=a[i][j];
}
}
for(int i=xx;i<=xx+3;i++){
for(int j=yy;j<=yy+3;j++){
a[i][j]=g[j-yy][3+xx-i];
}
}
}
bool check(int aa,int bb){
aa=aa*4;
bb=bb*4;
for(int i=aa;i<=aa+3;i++)
for(int j=bb;j<=bb+3;j++){
int num=a[i][j];
if(ck1[i][num]||ck2[j][num]){
return 0;
}
}
for(int i=aa;i<=aa+3;i++)
for(int j=bb;j<=bb+3;j++){
int num=a[i][j];
ck1[i][num]=1,ck2[j][num]=1;
}
return 1;
}
void uncheck(int aa,int bb){
aa=aa*4;
bb=bb*4;
for(int i=aa;i<=aa+3;i++)
for(int j=bb;j<=bb+3;j++){
int num=a[i][j];
ck1[i][num]=0,ck2[j][num]=0;
}
}
void dfs(int x, int y, int t) {
if (x == 4) {
if (t < ans) {
ans = t;
fas = as;
}
return;
}
for (int i = 0; i < 4; i++) {
if (!check(x,y)) {
roat(x, y);
continue;
}
as.push_back(Node{ x+1,y+1,i });
if (y == 3) {
dfs(x + 1, 0, t + i);
}
else dfs(x, y + 1, t + i);
as.pop_back();
uncheck(x,y);
roat(x,y);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
ans = 0x3f3f3f3f;
as.clear();
fas.clear();
memset(ck1, 0, sizeof ck1);
memset(ck2, 0, sizeof ck2);
for(int i=0;i<16;i++)for(int j=0;j<16;j++){
char x;
cin>>x;
int gx=get(x);
a[i][j]=gx;
}
dfs(0, 0, 0);
cout << ans << endl;
for (auto &x : fas) {
for (int i = 0; i < x.t; i++) {
cout << x.x << " " << x.y <<endl;
}
}
}
return 0;
}