hdu6341 Problem J. Let Sudoku Rotate (dfs)
Posted zhgyki
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu6341 Problem J. Let Sudoku Rotate (dfs)相关的知识,希望对你有一定的参考价值。
题目传送门
题意:
给你16个16宫格的数独,里面是0~F,你可以逆时针旋转里面的每个16宫格
问你它是从标准数独逆时针旋转多少次得到?
思路:
可以知道每个16宫已经是标准的了,接下来只要考虑每行、每列就行了
那么我们在dfs中就可以用两个行列两个数组来标记每个数字出现的次数,
大于1则不行
另外此时是逆时针来的,那么你就要顺时针回去
逆一次等于顺3次
参考博客:https://www.cnblogs.com/zquzjx/p/10326048.html
代码:
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define N 25 int g[N][N],G[N][N]; int R[N][N],C[N][N]; int ans; int get(int x,int y,int I,int J,int k) { if(k==1) return g[y+4-J+1][x+I]; else if(k==2) return g[x+4-I+1][y+4-J+1]; else if(k==3) return g[x][y+4-I+1]; else return g[x+I][y+J]; } bool Rotate(int x,int y,int k) { bool flag=1; for(int i=1;i<5;i++) { for(int j=1;j<5;j++) { int xx=(x-1)*4+i; int yy=(y-1)*4+j; G[xx][yy]=get(xx,yy,i,j,k);//cout<<xx<<" "<<yy<<" "<<G[xx][yy]<<endl; // cout<<(x-1)*4+i<<" "<<(y-1)*4+j<<endl; int r=++R[xx][G[xx][yy]]; int l=++C[yy][G[xx][yy]]; if(r>1||l>1) flag=0; } } return flag; } void reRotate(int x,int y) { for(int i=1;i<5;i++) { for(int j=1;j<5;j++) { int xx=(x-1)*4+i; int yy=(y-1)*4+j; --R[xx][G[xx][yy]]; --C[yy][G[xx][yy]]; G[xx][yy]=g[xx][yy]; } } } void dfs(int x,int y,int sum) { if(x==5) { ans=min(ans,sum); return ; } for(int i=0;i<=3;i++) { if(!Rotate(x,y,i)) { reRotate(x,y); continue; } if(y==4) dfs(x+1,1,sum+i); else dfs(x,y+1,sum+i); reRotate(x,y); } } int main() { int T; scanf("%d",&T); while(T--) { char s[25]; 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‘+1; else g[i][j]=s[j]-‘A‘+11; } } /*for(int i=1;i<=16;i++){ for(int j=1;j<=16;j++) printf("%d",g[i][j]); cout<<endl;}*/ memset(R,0,sizeof(R)); memset(C,0,sizeof(C)); ans=INF; dfs(1,1,0); printf("%d ",ans); } return 0; }
参考代码:
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define mem(i,j) memset(i,j,sizeof(i)) const int N=1e5+5; const int MOD=1e9+7; int G[20][20], g[20][20]; int R[20][20], C[20][20]; int ans; #define w(i) (i-1)*4 #define wG(i,j,I,J) G[w(i)+I][w(j)+J] int get(int r,int c,int x,int y,int k) { if(k==1) return wG(r,c,4-y+1,x); else if(k==2) return wG(r,c,4-x+1,4-y+1); else if(k==3) return wG(r,c,y,4-x+1); else return wG(r,c,x,y); } // 得到在r,c的块内x,y位置在第k种旋转之后的新数值 bool Rotate(int i,int j,int k) { bool OK=1; for(int I=1;I<=4;I++) for(int J=1;J<=4;J++) { int x=w(i)+I, y=w(j)+J; g[x][y]=get(i,j,I,J,k); int r=++R[x][g[x][y]]; int c=++C[y][g[x][y]]; if(r>1 || c>1) OK=0; // 这种旋转与之前其他块的旋转冲突 // 继续发展下去得到的一定是错误的 } return OK; } // 旋转i,j块 方式为第k种 void reRotate(int i,int j) { for(int I=1;I<=4;I++) for(int J=1;J<=4;J++) { int x=w(i)+I, y=w(j)+J; --R[x][g[x][y]]; --C[y][g[x][y]]; g[x][y]=G[x][y]; } } // 将i,j块的旋转取消 void dfs(int x,int y,int sum) { if(sum>ans) return; if(x==5) { ans=min(ans,sum); return; } // 四行四列16个块 到第五行说明已枚举了所有块的旋转 for(int i=0;i<=3;i++) { if(Rotate(x,y,i)==0) { reRotate(x,y); continue; } // 若发现这种旋转方式会冲突就跳过 if(y==4) dfs(x+1,1,sum+i); else dfs(x,y+1,sum+i); reRotate(x,y); } } // 搜索枚举16个块的旋转方式 int main() { int t; scanf("%d",&t); while(t--) { for(int i=1;i<=16;i++) { char s[20]; scanf("%s",s); for(int j=0;j<16;j++) { if(s[j]>=‘0‘ && s[j]<=‘9‘) G[i][j+1]=s[j]-‘0‘; else G[i][j+1]=s[j]-‘A‘+10; } } mem(R,0); mem(C,0); ans=INF; dfs(1,1,0); printf("%d ",ans); } return 0; }
以上是关于hdu6341 Problem J. Let Sudoku Rotate (dfs)的主要内容,如果未能解决你的问题,请参考以下文章
2018 Multi-University Training Contest 4 Problem J. Let Sudoku Rotate DFS+剪枝+矩阵旋转
Codeforces Gym 100342J Problem J. Triatrip 三元环
ACM ICPC 2016–2017, NEERC, Northern Subregional Contest Problem J. Java2016