【HDU 6341】暑期多校day4 Let Sudoku Rotate (搜索)

题目大意

原有一个16×16的数独,这个数独的某些宫(粗黑线划分的区域)被逆时针的旋转了未知次,给出某个数独被操作后的终态,求从原始状态到终态的最小操作次数。

详见 http://acm.hdu.edu.cn/showproblem.php?pid=6341 题目样例,解释很详细。


解题思路

直接进行枚举状态的搜索虽然加上优化可以过,但是考试的时候还是不太愿意写这种可能被强数据强行卡掉的算法,于是考虑这个数独的性质。

可以确定的是,这个数独的解只有两种:对于已知存在的一组解,把数独的所有宫再额外旋转两次即可得到第二组解;本来考虑题目性质的时候就想到了比较两种解法然后取min作为答案的,但是最后还是忘记写了,导致比赛时候交上去的第一发wa掉了。

首先只考虑每一个横行的宫,不考虑横行与横行之间的影响,每一个宫只有4种状态,分别暴力的枚举一横行四个宫的旋转次数需要 4^4=256 的时间复杂度。把宫的四个边界的存在的数压位预处理出来,这样每次检验是否合法只需要4步位运算。这样处理4个横行至多需要 4*256*4=4096次运算。

处理好每个横行后,横行和横行之间可能相互冲突,所以应该调整掉这些冲突。为了保证在调整的过程中始终保持横行内合法,某个横行只能不转or转两次。这样枚举每个横行是否需要转需要至多 2^4*4=64 次运算。

每个解都可以对应一个镜面解,比较两个解的大小,取min即为答案。
应该是全场最快吧,15ms?


代码

#include <bits/stdc++.h>
using namespace std;

inline char get_val(char ch) {
    if('0'<=ch && ch<='9') return ch-'0';
    return 10+ch-'A';
}
inline int add(int a,int b) {
    if(a+b<4) return a+b;
    return a+b-4;
}

#define bit(k) (1<<(k))
const int n=16;
int T;
char s[n+5][n+5];
int grid[n+5][n+5][4];
int rot[n+5][n+5], ROT[n+5];

void init() {
    register int i,j,k;
    for(i=0;i<n;++i) {
        ROT[i]=0;
        for(j=0;j<n;++j) {
            rot[i][j]=0;
            for(k=0;k<4;++k)
                grid[i][j][k]=0;
        }
    }
    return;
}

void calc_grid(int x,int y) {
    register int i,j;
    for(i=x*4;i<(x+1)*4;++i)
    for(j=y*4;j<(y+1)*4;++j) {
        if(i==4*x) grid[x][y][0]|=bit(s[i][j]);
        if(j==4*y) grid[x][y][1]|=bit(s[i][j]);
        if(i==4*x+3) grid[x][y][2]|=bit(s[i][j]);
        if(j==4*y+3) grid[x][y][3]|=bit(s[i][j]);
    }
    return;
}

bool check_row(int r) {
    int cur1=0;
    for(int j=0;j<4;++j) cur1|=grid[r][j][rot[r][j]];
    return (cur1==((1<<16)-1));
}

bool dfs_row(int x,int y) {
    if(y==4) return check_row(x);
    for(int i=0;i<4;++i) {
        rot[x][y]=i;
        if(dfs_row(x,y+1)) return true;
    }
    return false;
}

bool check_col(int c) {
    int cur=0;
    for(int i=0;i<4;++i) cur|=grid[i][c][(rot[i][c]+ROT[i]+1)%4];
    return (cur==((1<<16)-1));
}

bool dfs_col(int x,int y) {
    if(x==4) return check_col(y);
    for(int i=0;i<4;i+=2) {
        ROT[x]=i;
        if(dfs_col(x+1,y)) return true;
    }
    return false;
}

void work() {
    register int i,j;
    init();
    for(i=0;i<n;++i) {
        scanf("%s",s[i]);
        for(j=0;j<n;++j)
            s[i][j]=get_val(s[i][j]);
    }

    for(i=0;i<4;++i)
        for(j=0;j<4;++j)
            calc_grid(i,j);

    for(i=0;i<4;++i)
        dfs_row(i,0);
    dfs_col(0,0);

    for(i=0;i<4;++i) if(ROT[i])
        for(j=0;j<4;++j)
            rot[i][j]+=ROT[i];

    int ans1=0;
    for(i=0;i<4;++i)
        for(j=0;j<4;++j)
            ans1+=rot[i][j]%4;
    int ans2=0;
    for(i=0;i<4;++i)
        for(j=0;j<4;++j)
            ans2+=(rot[i][j]+2)%4;

    printf("%d\n",min(ans1,ans2));
    return;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input0.txt","r",stdin);
#endif
    for(scanf("%d",&T);T;T--)
        work();

    return 0;
}
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页