1. 程式人生 > >2018多校第4場1010 && HDU6341 ProblemJ. Let Sudoku Rotate

2018多校第4場1010 && HDU6341 ProblemJ. 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;
}