HDU 6341 (Problem J. Let Sudoku Rotate) 深搜+剪枝

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 [Math Processing Error] grids, which consist of [Math Processing Error] 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 [Math Processing Error] [Math Processing Error] denoting the number of test cases.
Each test case consists of exactly [Math Processing Error] lines with [Math Processing Error] 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.
 

 

题意:一个填好的16X16的数独,其中某些4x4的大格子被任意的逆时针旋转了n次,每次90°,问:整个数独最少被旋转了几次
思路:这就是一个简单的深搜剪枝题。抽象一下,就相当于一个4X4的格子,每个格子可以填0-3数字,然后按照具体规则填。
   具体来说,就是把每个4x4的顺时针旋转k(取0-3)次,填到新的16x16的数独里,每次填好后检查一下行列是否符合数独规则,若复合则继续填,不符合就回溯
      找出所有正确的可能,输出其中旋转次数之和最小的情况
代码:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stack>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define maxx 0x3f3f3f3f
using namespace std;

stack<int> q;
int shudu[18][18];
int newshudu[17][17];
int map_hang[18][18];
int map_lie[18][18];
int t;
string s;
int ans = maxx;

void incase() {
    int t;
    for (int i = 1; i <= 16; i++) {
        cin >> s;
        t = 0;
        for (int j = 1; j <= 16; j++) {
            if ('9' - s[t] >= 0) {
                shudu[i][j] = s[t] - '0';
            }
            else {
                shudu[i][j] = s[t] - 'A' + 10;
            }
            t++;
        }
    }
}
void xuanzhuan(int i, int j, int k) {
    int x = (i - 1) * 4 + 1;
    int y = (j - 1) * 4 + 1;
    for (int a = 0; a < 4; a++) {
        for (int b = 0; b < 4; b++) {
            if (k == 0) {
                newshudu[x + a][y + b] = shudu[x + a][y + b];
            }
            else if (k == 1) {
                newshudu[x + a][y + b] = shudu[x + 3 - b][y + a];
            }
            else if (k == 2) {
                newshudu[x + a][y + b] = shudu[x + 3 - a][y + 3 - b];
            }
            else if (k == 3) {
                newshudu[x + a][y + b] = shudu[x + b][y + 3 - a];
            }

            map_hang[x + a][newshudu[x + a][y + b]]++;
            map_hang[x + a][17] += map_hang[x + a][newshudu[x + a][y + b]];
            map_lie[y + b][newshudu[x + a][y + b]]++;
            map_lie[y + b][17] += map_lie[y + b][newshudu[x + a][y + b]];
        }
    }
}
void rexuanzhuan(int i, int j) {
    int x = (i - 1) * 4 + 1;
    int y = (j - 1) * 4 + 1;
    for (int a = x; a <= x + 3; a++) {
        for (int b = y; b <= y + 3; b++) {
            map_hang[a][17] -= map_hang[a][newshudu[a][b]];
            map_hang[a][newshudu[a][b]]--;
            map_lie[b][17] -= map_lie[b][newshudu[a][b]];
            map_lie[b][newshudu[a][b]]--;

            newshudu[a][b] = 0;
        }
    }
}
bool isright(int a, int b) {
    int x = a * 4;
    int y = b * 4;
    for (int i = 0; i < 4; i++) {
        if (map_hang[x - i][17] != b * 4) {
            return 0;
        }
        if (map_lie[y - i][17] != a * 4) {
            return 0;
        }
    }
    return 1;
}
void dfs(int a, int b, int tmp) {
    if (a > 4) {
        ans = min(ans,tmp);
        q.pop();
        if (b == 1) {
            rexuanzhuan(a - 1, 4);
            return;
        }
        else {
            rexuanzhuan(a, b - 1);
            return;
        }
    }

    for (int k = 0; k < 4; k++) {
        xuanzhuan(a, b, k);
        tmp += k;
        q.push(tmp);
        if (isright(a, b)) {
            if (b + 1 <= 4) {
                dfs(a, b + 1, tmp);
                tmp -= k;
            }
            else {
                dfs(a + 1, 1, tmp);
                tmp -= k;
            }
        }
        else {
            rexuanzhuan(a, b);
            tmp -= k;
            q.pop();
        }
    }
    if (!(a - 1) && !(b - 1)) {
        return;
    }
    if (b == 1) {
        rexuanzhuan(a-1, 4);
    }
    else {
        rexuanzhuan(a, b - 1);
    }
    q.pop();
}

int main() {
    fio;
    cin >> t;
    while (t--)
    {
        memset(map_hang, 0, sizeof map_hang);
        memset(map_lie, 0, sizeof map_lie);
        memset(shudu, 0, sizeof shudu);
        memset(newshudu, 0, sizeof newshudu);
        while (!q.empty()){
            q.pop();
        }
        ans = maxx;

        incase();

        dfs(1, 1,0);

        cout << ans << endl;
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/the-way-of-cas/p/9415912.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值