zoukankan      html  css  js  c++  java
  • 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;
    }
    View Code

    参考代码:

    #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;
    }
    View Code
  • 相关阅读:
    equa与==的区别
    使用Log4j进行日志操作
    动态代理的步骤
    批量插入使用SqlBulkCopy
    SQL之开窗函数二——在复杂场景中的实际运用
    SQL Server数据类型详解
    SQL Server遍历表的几种方法
    SQL Server之表变量
    SQL Server之字符串处理函数
    SQL Server之String_Split函数(SQL Server2016版本以上使用)
  • 原文地址:https://www.cnblogs.com/zhgyki/p/10397095.html
Copyright © 2011-2022 走看看