2018 Multi-University Training Contest 4 Problem J. Let Sudoku Rotate 【DFS+剪枝+矩阵旋转】

解决一个16x16的数独谜题,通过旋转4x4区域来还原数独,寻找最少的操作次数。

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6341

Problem J. Let Sudoku Rotate

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1363    Accepted Submission(s): 717


Problem Description
Sudoku is a logic-based, combinatorial number-placement puzzle, which is popular around the world.
In this problem, let us focus on puzzles with  16×16 grids, which consist of 4×4 regions. The objective is to fill the whole grid with hexadecimal digits, i.e. 0123456789ABCDEF, so that each column, each row, and each region contains all hexadecimal digits. The figure below shows a solved sudoku.


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Yesterday, Kazari solved a sudoku and left it on the desk. However, Minato played a joke with her - he performed the following operation several times.
* Choose a region and rotate it by 90 degrees counterclockwise.
She burst into tears as soon as she found the sudoku was broken because of rotations.
Could you let her know how many operations her brother performed at least?
 

 

Input
The first line of the input contains an integer  T (1T103) denoting the number of test cases.
Each test case consists of exactly 16 lines with 16 characters each, describing a broken sudoku.
 

 

Output
For each test case, print a non-negative integer indicating the minimum possible number of operations.
 

 

Sample Input
1 681D5A0C9FDBB2F7 0A734B62E167D9E5 5C9B73EF3C208410 F24ED18948A5CA63 39FAED5616400B74 D120C4B7CA3DEF38 7EC829A085BE6D51 B56438F129F79C2A 5C7FBC4E3D08719F AE8B1673BF42A58D 60D3AF25619C30BE 294190D8EA57264C C7D1B35606835EAB AF52A1E019BE4306 8B36DC78D425F7C9 E409492FC7FA18D2
 

 

Sample Output
5
Hint
The original sudoku is same as the example in the statement.
 

 

Source

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

题意概括:

有一个 16×16 的已经打乱的数独,4×4为一宫,每次可对宫顺时针旋转 90 度。最少要操作多少次可以还原数独。

 

解题思路:

递归每一宫的左上角坐标 (x, y) ,DFS枚举每一宫的旋转次数,可知这样暴力的方案数为 4^(16) =  4294967296,需要剪枝。

由于数独的特殊性,我们枚举下一个状态前可以先判断上一个状态是否满足条件,即每行每列的数都要单独存在。

对于矩阵旋转的操作,找一下下标的规律:第一行变成第一列,第二行变成第二列,第三行变成第三列.....

AC code:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<vector>
 6 #include<queue>
 7 #include<cmath>
 8 #include<set>
 9 #define INF 0x3f3f3f3f
10 #define LL long long
11 using namespace std;
12 const int MAXN = 20;
13 char str[MAXN][MAXN];
14 int mmp[MAXN][MAXN];
15 int tmp[MAXN][MAXN];
16 bool vis[MAXN];
17 int ans;
18 
19 void rt(int x, int y)
20 {
21     int rx = 4*x, ry = 4*y-3;
22     for(int i = 4*x-3; i <= 4*x; i++){
23         rx = 4*x;
24         for(int k = 4*y-3; k <= 4*y; k++){
25             tmp[i][k] = mmp[rx][ry];
26             rx--;
27         }
28         ry++;
29     }
30 
31     for(int i = 4*x-3; i <= 4*x; i++){
32         for(int j = 4*y-3; j <= 4*y; j++){
33             mmp[i][j] = tmp[i][j];
34         }
35     }
36 
37 }
38 
39 bool check(int x, int y)
40 {
41     for(int i = 4*x-3; i <= 4*x; i++){
42         memset(vis, 0, sizeof(vis));
43         for(int j = 1; j <= 4*y; j++){
44             if(vis[mmp[i][j]]){
45                     return false;
46             }
47             vis[mmp[i][j]] = true;
48         }
49     }
50     for(int i = 4*y-3; i <= 4*y; i++){
51         memset(vis, 0, sizeof(vis));
52         for(int j = 1; j <= 4*x; j++){
53             if(vis[mmp[j][i]]){
54                 return false;
55             }
56             vis[mmp[j][i]] = true;
57         }
58     }
59     return true;
60 }
61 
62 void dfs(int x, int y, int cnt)
63 {
64     if(x > 4){
65         ans = min(ans, cnt);
66         return;
67     }
68     for(int i = 0; i < 4; i++){
69         if(i) rt(x, y);
70         if(check(x, y)){
71             if(y < 4) dfs(x, y+1, cnt+i);
72             else dfs(x+1, 1, cnt+i);
73         }
74     }
75     rt(x, y);
76 }
77 
78 int main()
79 {
80     int T_case;
81     scanf("%d", &T_case);
82     while(T_case--){
83         for(int i = 0; i < 16; i++){
84             scanf("%s", str[i]);
85         }
86         for(int i = 0; i < 16; i++){
87             for(int j = 0; j < 16; j++){
88                 if(str[i][j] >= '0' && str[i][j] <= '9'){
89                     mmp[i+1][j+1] = str[i][j]-'0';
90                 }
91                 else mmp[i+1][j+1] = str[i][j]-'A'+10;
92             }
93         }
94         ans = INF;
95         dfs(1, 1, 0);
96         printf("%d\n", ans);
97     }
98     return 0;
99 }
View Code

 

第三方支付功能的技术人员;尤其适合从事电商、在线教育、SaaS类项目开发的工程师。; 使用场景及目标:① 实现微信与支付宝的Native、网页/APP等主流支付方式接入;② 掌握支付过程中关键的安全机制如签名验签、证书管理与敏感信息保护;③ 构建完整的支付闭环,包括下单、支付、异步通知、订单状态更新、退款与对账功能;④ 通过定时任务处理内容支付超时与概要状态不一致问题:本文详细讲解了Java,提升系统健壮性。; 阅读应用接入支付宝和建议:建议结合官方文档与沙微信支付的全流程,涵盖支付产品介绍、开发环境搭建箱环境边学边练,重点关注、安全机制、配置管理、签名核心API调用及验签逻辑、异步通知的幂等处理实际代码实现。重点与异常边界情况;包括商户号与AppID获取、API注意生产环境中的密密钥与证书配置钥安全与接口调用频率控制、使用官方SDK进行支付。下单、异步通知处理、订单查询、退款、账单下载等功能,并深入解析签名与验签、加密解密、内网穿透等关键技术环节,帮助开发者构建安全可靠的支付系统。; 适合人群:具备一定Java开发基础,熟悉Spring框架和HTTP协议,有1-3年工作经验的后端研发人员或希望快速掌握第三方支付集成的开发者。; 使用场景及目标:① 实现微信支付Native模式与支付宝PC网页支付的接入;② 掌握支付过程中核心的安全机制如签名验签、证书管理、敏感数据加密;③ 处理支付结果异步通知、订单状态核对、定时任务补偿、退款及对账等生产级功能; 阅读建议:建议结合文档中的代码示例与官方API文档同步实践,重点关注支付流程的状态一致性控制、幂等性处理和异常边界情况,建议在沙箱环境中完成全流程测试后再上线。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值