一、题意
Sudoku is a logic-based, combinatorial number-placement puzzle, which is popular around the world.
In this problem, let us focus on puzzles with 16×16 grids, which consist of 4×4 regions. The objective is to fill the whole grid with hexadecimal digits, i.e. 0123456789ABCDEF, so that each column, each row, and each region contains all hexadecimal digits. The figure below shows a solved sudoku.
考虑一个完成后的数独游戏局面,将16*16的局面分割成4*4的小方块,随机旋转小方块得到一个新的局面,现在给出新的局面,问你最少旋转几次可以得到一个完成的局面。
二、解题思路。
首先考虑暴力搜索,4^16次方次旋转——来自每个小方块4次旋转,一共16个小方块。
但是考虑数独游戏的特征,每走一步都可以判断当前的选择是否合法——因此可以进行剪枝——判断下当前所在方块、所在形状的合法性——已经取到的行、列是否合法。
处于某种我证明不了的原因认为,这种方式将会把剪枝操作剪到足够小,以至于31ms就可以搞定1000组输入。
#include<bits/stdc++.h> using namespace std; #define ll long long const int MAXN=1233; char mapp[MAXN][MAXN]; int ans=0; int tran(char c) { if(c>='0'&&c<='9')return c-'0'; else return c-'A'+10; } bool check_left(int a,int b) { // int x = a*4; int endd = (b+1)*4; if(b == 0)return true; for(int i=0;i<4;++i) { int x = a*4 +i; int ch[16]; memset(ch,0,sizeof(ch)); for(int j=0;j<endd;++j) { ch[tran(mapp[x][j])]++; if(ch[tran(mapp[x][j])] == 2)return false; } }return true; } bool check_up(int a,int b) { int endd = (a+1)*4; if(a == 0)return true; for(int j=0;j<4;++j) { int y = b*4+j; int ch[16]; memset(ch,0,sizeof(ch)); for(int i=0;i<endd;i++) { ch[tran(mapp[i][y])]++; if(ch[tran(mapp[i][y])] == 2)return false; } }return true; } bool check(int a,int b) { return check_left(a,b)&&check_up(a,b); } bool check(int l) { for(int i=0;i<4;++i) { int x = l*4+i; int ch[16]; memset(ch,0,sizeof(ch)); for(int j=0;j<16;++j) { ch[tran(mapp[x][j])]++; if(ch[tran(mapp[x][j])]==2)return false; } } return true; } void change(int a,int b) { int x = a*4; int y = b*4; int tmp = mapp[x][y]; mapp[x][y] = mapp[x+0][y+3]; mapp[x+0][y+3] = mapp[x+3][y+3]; mapp[x+3][y+3] = mapp[x+3][y+0]; mapp[x+3][y+0] = tmp; tmp = mapp[x+0][y+1]; mapp[x+0][y+1] = mapp[x+1][y+3]; mapp[x+1][y+3] = mapp[x+3][y+2]; mapp[x+3][y+2] = mapp[x+2][y+0]; mapp[x+2][y+0] = tmp; tmp = mapp[x+0][y+2]; mapp[x+0][y+2] = mapp[x+2][y+3]; mapp[x+2][y+3] = mapp[x+3][y+1]; mapp[x+3][y+1] = mapp[x+1][y+0]; mapp[x+1][y+0] = tmp; tmp = mapp[x+1][y+1]; mapp[x+1][y+1] = mapp[x+1][y+2]; mapp[x+1][y+2] = mapp[x+2][y+2]; mapp[x+2][y+2] = mapp[x+2][y+1]; mapp[x+2][y+1] = tmp; } void change1(int a,int b) { int x = a*4; int y = b*4; int tmp = mapp[x][y]; mapp[x][y] = mapp[x+3][y+0]; mapp[x+3][y+0] = mapp[x+3][y+3]; mapp[x+3][y+3] = mapp[x+0][y+3]; mapp[x+0][y+3] = tmp; tmp = mapp[x+0][y+2]; mapp[x+0][y+2] = mapp[x+1][y+0]; mapp[x+1][y+0] = mapp[x+3][y+1]; mapp[x+3][y+1] = mapp[x+2][y+3]; mapp[x+2][y+3] = tmp; tmp = mapp[x+0][y+1]; mapp[x+0][y+1] = mapp[x+2][y+0]; mapp[x+2][y+0] = mapp[x+3][y+2]; mapp[x+3][y+2] = mapp[x+1][y+3]; mapp[x+1][y+3] = tmp; tmp = mapp[x+1][y+1]; mapp[x+1][y+1] = mapp[x+2][y+1]; mapp[x+2][y+1] = mapp[x+2][y+2]; mapp[x+2][y+2] = mapp[x+1][y+2]; mapp[x+1][y+2] = tmp; } bool search(int a,int b,int summ) { // cout<<"search : "<<a<<" "<<b<<" step: "<<summ<<endl; if(b==4) { if(check(a)){ ans += summ; return true; } return false; } if(search(a,b+1,summ))return true; for(int i=0;i<3;++i) { change1(a,b); if(search(a,b+1,summ+1+i))return true; } change1(a,b); return false; } bool dfs(int now,int summ) { int a = now/4; int b = now%4; if(now == 16) { ans = min(ans,summ); return true; } if(check(a,b)&&dfs(now+1,summ)); for(int i=0;i<3;++i) { change1(a,b); if(!check(a,b))continue; dfs(now+1,summ+i+1); } change1(a,b); return false; } void show() { for(int i=0;i<16;++i) { for(int j=0;j<16;++j) { cout<<mapp[i][j]; }cout<<endl; } } void init() { ans = INT_MAX; for(int i=0;i<16;++i)gets(mapp[i]); dfs(0,0); cout<<ans<<" "; } int main() { int t; // cin>>t; scanf("%d ",&t); while(t--)init(); return 0; }