• hdu6341 /// 模拟 DFS+剪枝


    题目大意:

    将16行16列的矩阵分成四行四列共16块

    矩阵的初始状态每行及每列都不会出现重复的元素

    给定一个已旋转过某些块的矩阵 判断其是由初始状态最少经过几次旋转得到的

    DFS枚举16个块的旋转方式

    DFS过程中直接进行旋转 一旦发现旋转结果与之前枚举的块的旋转结果相悖就剪枝

    这个剪枝已经足够AC 也不妨在加一条当前旋转次数比之前得到的可能答案大就剪枝

    #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
  • 相关阅读:
    记录一次无法很好解决的问题
    java与进制转换
    花了点时间写了下测试框架
    利用eclipse或者pycharm编写monkeyrunner脚本,cmd打开应用“转转”并截图保存到D盘
    Instrumentation
    关于学生机受控应用的问题总结
    忙里偷闲一天
    linux下python3的安装(已安装python2的情况下)
    ROS上利用usb_cam读取摄像头图像
    ch8 -- directMethod
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10326048.html
Copyright © 2020-2023  润新知