HDU-6341 Problem J. Let Sudoku Rotate(dfs 剪枝)
题目:有一个4*4*4*4的数独,每一横每一竖每一个小方块中都无重复的字母,即都为0-9,A-F.。有一个已经填好的数独,若干个4*4的方块被逆时针拧转了若干次,问拧转回来至少需要多少次。
分析:很明显的一道深授暴力题 , 一开始不知道是怎么收才好 , 那时候考虑说假如同一行或者同一列都有区域要反转 , 我该怎么找 , 后来看了题解后发现 , 我只要保证每次旋转后 , 该区域与此前的区域是满足数独的就好 , 子问题的不重复不会影响到大问题的不重复 。深搜索的能力需要加强
#include<bits/stdc++.h> using namespace std ; int G[20][20],tmp[20][20]; bool vis[20]; int ans; void rot(int x , int y) { for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) tmp[j][4-i+1]=G[(x-1)*4+i][(y-1)*4+j]; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) G[(x-1)*4+i][(y-1)*4+j]=tmp[i][j]; } bool check(int x , int y) { for(int i=4*x-3 ; i<=x*4 ; i++) { memset(vis,0,sizeof(vis)); for(int j=1 ; j<=4*y ; j++) { if(!vis[G[i][j]]) vis[G[i][j]]=1; else return 0; } } for(int i=y*4-3 ; i<=y*4 ; i++) { memset(vis,0,sizeof(vis)); for(int j=1 ; j<=4*x ; j++) { if(!vis[G[j][i]]) vis[G[j][i]]=1; else return 0; } } return 1; } void dfs(int x , int y , int sum) { if(ans<=sum) return ; int X=x , Y=y+1; if(x==5) { ans=sum; return ; } if(Y==5) { X++; Y=1; } for(int i=0 ; i<4 ; i++) { if(i) rot(x,y); if(check(x,y)) { //printf("520"); dfs(X,Y,sum+i); } } rot(x,y); } char s[20]; int main() { int t; scanf("%d",&t); while(t--) { for(int i=1 ; i<=16 ; i++) { scanf("%s",s+1); for(int j=1 ; j<=16 ; j++) { if(s[j]>='0'&&s[j]<='9') G[i][j]=s[j]-'0'; else G[i][j]=s[j]-'A'+10; } } ans=0x3f3f3f3f; dfs(1,1,0); printf("%d\n",ans); } return 0; }