码迷,mamicode.com
首页 > 其他好文 > 详细

hdu6341 /// 模拟 DFS+剪枝

时间:2019-01-27 14:42:05      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:opened   元素   分享   数值   printf   结果   const   main   scanf   

题目大意:

将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\n",ans);
    }

    return 0;
}
View Code

 

hdu6341 /// 模拟 DFS+剪枝

标签:opened   元素   分享   数值   printf   结果   const   main   scanf   

原文地址:https://www.cnblogs.com/zquzjx/p/10326048.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!