HDU - 6341 - Problem J. Let Sudoku Rotate
题意:
一个16*16的数独,给你将其每块逆时针旋转一些次数后的状态,求出其恢复到数独条件满足最少要旋转多少次。
模拟每块逆时针旋转。
每块旋转结束后在该块左上角就已经确定了,可以判断每行每列是否有相同的,用以剪枝。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
char mp[20][20];
int T, s[20][20], ans = 50;
void move_(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4){
// 1 -> 4 -> 3 -> 2 -> 1
// 对应四个点旋转一遍
swap(s[x1][y1], s[x4][y4]);
swap(s[x1][y1], s[x3][y3]);
swap(s[x1][y1], s[x2][y2]);
}
void change(int x, int y){
// 小矩形顺时针旋转一次
for(int i=0;i<3;i++){
move_(x+i, y, x+3, y+i, x+3-i, y+3, x, y+3-i);
}
move_(x+1, y+1, x+2, y+1, x+2, y+2, x+1, y+2);
}
bool check(int x, int y){
for(int i=0;i<4;i++){
int t = 0;
for(int j=1;j<=y+3;j++) {
if(t & 1<<s[x+i][j]) return 0;
t |= 1<<s[x+i][j];
}
t = 0;
for(int j=1;j<=x+3;j++){
if(t & 1<<s[j][y+i]) return 0;
t |= 1<<s[j][y+i];
}
}
return 1;
}
void dfs(int pos, int step){
if(step >= ans) return;
if(pos == 16) {
ans = step; return;
}
int x = (pos / 4) * 4 + 1;
int y = (pos % 4) * 4 + 1;
for(int i=0;i<4;i++) {
if(i) change(x, y);
if(check(x, y)) dfs(pos+1, step+i);
}
change(x, y);
}
int main()
{
scanf("%d", &T);
while(T--){
for(int i=1;i<=16;i++) scanf("%s", mp[i]+1);
for(int i=1;i<=16;i++) {
for(int j=1;j<=16;j++) {
s[i][j] = mp[i][j] - (mp[i][j]<='9' ? '0' : 'A' - 10);
}
}
ans = 50;
dfs(0,0);
printf("%d\n", ans);
}
return 0;
}