1. 程式人生 > >HDU 6341 Let Sudoku Rotate (DFS)

HDU 6341 Let Sudoku Rotate (DFS)

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.


Yesterday, Kazari solved a sudoku and left it on the desk. However, Minato played a joke with her - he performed the following operation several times.
* Choose a region and rotate it by 90 degrees counterclockwise.
She burst into tears as soon as she found the sudoku was broken because of rotations.
Could you let her know how many operations her brother performed at least?

Input

The first line of the input contains an integer T (1≤T≤103) denoting the number of test cases.
Each test case consists of exactly 16 lines with 16 characters each, describing a broken sudoku.

Output

For each test case, print a non-negative integer indicating the minimum possible number of operations.

Sample Input

1

681D5A0C9FDBB2F7

0A734B62E167D9E5

5C9B73EF3C208410

F24ED18948A5CA63

39FAED5616400B74

D120C4B7CA3DEF38

7EC829A085BE6D51

B56438F129F79C2A

5C7FBC4E3D08719F

AE8B1673BF42A58D

60D3AF25619C30BE

294190D8EA57264C

C7D1B35606835EAB

AF52A1E019BE4306

8B36DC78D425F7C9

E409492FC7FA18D2

Sample Output

5

Hint

The original sudoku is same as the example in the statement.

題目大意:有一個16*16的數獨矩陣,每個4*4的小數獨矩陣每次能逆時針旋轉90度,現在給出旋轉後的矩陣,求出各個小矩陣最小旋轉的次數和。

思路:比賽的時候看到各路大神15ms過就慫了,以為不是搜尋會有規律神馬的........結果...還就是單純的搜尋題。(開始自閉)。用DFS加減枝,列舉旋轉次數判斷旋轉後行列是否滿足數獨的條件就行了。結果自己的出來是200+ms,,,,一想到一大堆神仙減枝到15ms就心痛.......

程式碼如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<string>
using namespace std;
char s[20][20];
char p[5][5];
int vis[20];
void fun(int x,int y)//順時針旋轉矩陣90度
{
    for(int i=1,a=y;i<=4;i++,a++)
    {
    	for(int j=1,b=x;j<=4;j++,b--) p[i][j]=s[b][a];
	}
    for(int j=1,a=y;j<=4;j++,a++)
    {
    	for(int i=4,b=x;i>=1;i--,b--) s[b][a]=p[i][j];
	}
}
int g(char c){return (c>='0'&&c<='9')?c-'0':c-'A'+10;}
int fun1(int x)
{
    for(int i=x-3;i<=x;i++)//每行不能有重複出現的數
    {
        memset(vis,0,sizeof vis);
        for(int j=1;j<=16;j++)
        {
            if(vis[g(s[i][j])]!=0) return 0;
            vis[g(s[i][j])]=1;
        }
    }
    for(int j=1;j<=16;j++)//每列不能有重複出現的數
    {
        memset(vis,0,sizeof vis);
        for(int i=1;i<=x;i++)
        {
            if(vis[g(s[i][j])]!=0) return 0;
            vis[g(s[i][j])]=1;
        }
    }
    return 1;
}
int s1;
void dfs(int k,int num)//k表示列舉到第k行,num表示旋轉次數
{
	if(num>s1) return;
    if(k>16)
	{
	    s1=min(s1,num);
		return;
	}
    for(int a=0;a<=3;a++,fun(k,1))//列舉這4個子矩陣的旋轉次數
    {
    	for(int b=0;b<=3;b++,fun(k,5))
    	{
    		for(int c=0;c<=3;c++,fun(k,9))
    		{
    			for(int d=0;d<=3;d++,fun(k,13))
    			{
    				if(fun1(k)==0) continue;//判斷前k行是否滿足數獨的條件
                    dfs(k+4,num+a+b+c+d);
				}
			}
		}
	}  
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=1;i<=16;i++)
		scanf("%s",s[i]+1);
		s1=16*3;
        dfs(4,0);
        printf("%d\n",s1);
    }
    return 0;
}