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
",ans);
    }
  return  0;
}
View Code
原文地址:https://www.cnblogs.com/shuaihui520/p/10324549.html