2018多校第4场1010 && HDU6341 ProblemJ. Let Sudoku Rotate

题目链接:Let Sudoku Rotate

 

思路分析:大矩形分为16个子块,搜索即可。数独限制性很强,可行性剪枝+最优化剪枝....

看了一下标程,写的很精简,学习了...

 

代码如下:

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;

const int maxn = 20;
char s[maxn][maxn];
int a[maxn][maxn];
int b[10][10];
int row[maxn][maxn],col[maxn][maxn];
int ans;

inline int getc(char c){
   if (isdigit(c)) return c-'0';
   return c-'A'+10;
}

inline int Min(int x, int y) {return x<y?x:y;}

inline void add(int idx, int idy, int val) {
    for (int i=idx<<2; i<(idx+1)<<2; ++i) {
        for (int j=idy<<2; j<(idy+1)<<2; ++j)
            row[i][a[i][j]] += val, col[j][a[i][j]] += val;
    }
}

inline int Rotate(int idx, int idy) {
    for (int i=idx<<2; i<(idx+1)<<2; ++i) {
        for (int j=idy<<2; j<(idy+1)<<2; ++j) {
            --row[i][a[i][j]]; --col[j][a[i][j]];
            b[j-(idy<<2)][((idx+1)<<2)-i-1] = a[i][j];
        }
    }

    int res = 1;
    for (int i=idx<<2; i<(idx+1)<<2; ++i) {
        for (int j=idy<<2; j<(idy+1)<<2; ++j) {
            a[i][j] = b[i-(idx<<2)][j-(idy<<2)];
            if ( (++row[i][a[i][j]]>1) || (++col[j][a[i][j]]>1) ) res = 0;
        }
    }
    return res;
}

void dfs(int idx,int idy, int num){
   if (idx>=4) {
       ans = Min(ans,num);
       return ;
   }
   if (num >= ans) return;
   add(idx,idy,1);
   for (int i=1; i<=4; ++i) {
      if (Rotate(idx,idy)) dfs(idy == 3?idx+1:idx,idy == 3?0:idy+1,num+i%4);
   }
   add(idx,idy,-1);
}

int main(){
    int T; scanf("%d",&T);
    register int i,j;
    while (T--){
       for (i=0; i<16; ++i) {
          scanf("%s",s[i]);
          for (j=0; j<16; ++j) a[i][j] = getc(s[i][j]);
       }

       /*for (i=0; i<16; ++i) {
          for (j=0; j<16; ++j) printf("%d",a[i][j]); puts("");
       }*/
       memset(row,0,sizeof(row));
       memset(col,0,sizeof(col));
       ans = 1<<30;
       dfs(0,0,0);
       printf("%d\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值