HDU 6341 Problem J. Let Sudoku Rotate 【暴力剪枝】

题目大意:

现在有个已经完成的$16 \times 16$的数独(即满足数独的要求),它的某些部分被逆时针旋转过了。已知每次旋转的角度为90°,问最少经过多少次旋转能将它转回原样。

解题思路:

因为数独要求很严格,所以我们可以直接进行搜索 + 剪枝。

PS:给的标程是真的好看,特别是旋转的那一部分,既简洁又优美。Orz。

ACcode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

char s[16];
int res, a[16][16], r[16][16], c[16][16], b[4][4];

int trans(char ch)
{
if(isdigit(ch))
return ch - '0';
return ch - 'A' + 10;
}

void add(int ip, int jp, int val)
{
for(int i = ip * 4; i < (ip + 1) * 4; ++i)
{
for(int j = jp * 4; j < (jp + 1) * 4; ++j)
{
r[i][a[i][j]] += val;
c[j][a[i][j]] += val;
}
}
}

//进行旋转操作
bool rot(int ip, int jp)
{
for(int i = ip * 4; i < (ip + 1) * 4; ++i)
{
for(int j = jp * 4; j < (jp + 1) * 4; ++j)
{
//先把要旋转的部分拿出来
--r[i][a[i][j]];
--c[j][a[i][j]];
b[j - jp * 4][(ip + 1) * 4 - i - 1] = a[i][j];
}
}
bool flag = true;
for(int i = ip * 4; i < (ip + 1) * 4; ++i)
{
for(int j = jp * 4; j < (jp + 1) * 4; ++j)
{
//将拿出来的部分进行归位
a[i][j] = b[i - ip * 4][j - jp * 4];
//出现了不符合要求的情况
if((++r[i][a[i][j]] > 1) || (++c[j][a[i][j]] > 1))
flag = false;
}
}
return flag;
}

void dfs(int ip, int jp, int now)
{
if(ip == 4 && jp == 0)
{
res = min(res, now);
return ;
}
//状态改变
add(ip, jp, 1);
if(now >= res) return ;
for(int i = 1; i <= 4; ++i)
{
//旋转i次
if(rot(ip, jp))
dfs(jp == 3 ? ip + 1 : ip, jp == 3 ? 0 : jp + 1, now + (i & 3));
}
//状态恢复
add(ip, jp, -1);
}

int main()
{
int t;
scanf("%d", &t);
while(t--)
{
for(int i = 0; i < 16; ++i)
{
scanf("%s", s);
for(int j = 0; j < 16; ++j)
{
a[i][j] = trans(s[j]);
}
}
memset(r, 0, sizeof(r));
memset(c, 0, sizeof(c));
res = 16 * 4;
dfs(0, 0, 0);
printf("%d\n", res);
}
return 0;
}
Donate comment here
0%