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

参考代码:

#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;
}

原文地址:https://www.cnblogs.com/zhgyki/p/10397095.html

时间: 2024-09-29 07:40:57

hdu6341 Problem J. Let Sudoku Rotate (dfs)的相关文章

HDU-6341 Problem J. Let Sudoku Rotate(dfs 剪枝)

题目:有一个4*4*4*4的数独,每一横每一竖每一个小方块中都无重复的字母,即都为0-9,A-F..有一个已经填好的数独,若干个4*4的方块被逆时针拧转了若干次,问拧转回来至少需要多少次. 分析:很明显的一道深授暴力题 , 一开始不知道是怎么收才好 , 那时候考虑说假如同一行或者同一列都有区域要反转 , 我该怎么找 , 后来看了题解后发现 , 我只要保证每次旋转后 , 该区域与此前的区域是满足数独的就好 , 子问题的不重复不会影响到大问题的不重复 .深搜索的能力需要加强 #include<bit

2018 Multi-University Training Contest 4 Problem J. Let Sudoku Rotate 【DFS+剪枝+矩阵旋转】

任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6341 Problem J. Let Sudoku Rotate Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 1363    Accepted Submission(s): 717 Problem Description Sudoku i

hdu第4场j.Let Sudoku Rotate

Problem J. Let Sudoku Rotate Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 771 Accepted Submission(s): 417 Problem Description Sudoku is a logic-based, combinatorial number-placement puzzle, w

迷宫问题(maze problem)——深度优先(DFS)与广度优先搜索(BFS)求解

1.问题简介 给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem). 迷宫可以以二维数组来存储表示.0表示通路,1表示障碍.注意这里规定移动可以从上.下.左.右四方方向移动.坐标以行和列表示,均从0开始,给定起点(0,0)和终点(4,4),迷宫表示如下: int maze[5][5]={ {0,0,0,0,0}, {0,1,0,1,0}, {0,1,1,0,0}, {0,1,1,0,1}, {0,0,0,0,0} }; 那么下面的迷宫就有两条

hdu 1016 Prime Ring Problem (dfs)

一切见注释. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; bool vis[22]; int n; int ans[22]; int top; bool isprime(int x)//判断素数 { for(int i=2;i<x;i++) if(x%i==0)return false; return

HDU 2209 翻纸牌游戏(dfs)

翻纸牌游戏 Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2180    Accepted Submission(s): 787 Problem Description 有一种纸牌游戏,很有意思,给你N张纸牌,一字排开,纸牌有正反两面,开始的纸牌可能是一种乱的状态(有些朝正,有些朝反),现在你需要整理这些纸牌.但是麻烦的是,每当你翻一张

poj 1724 ROADS(dfs)

http://poj.org/problem?id=1724 大致题意:N个城市由R条单向路连通,每条路(S,D)之间有两个因素:路的长度L和路的花费T.现要从城市1到达城市N,求花费在K以内的最短路程. 思路:很明显的dfs(他们都说很明显的spfa...).不过dfs有几点注意的地方: 建立邻接表不能用vector存,要用链表的形式,采用头插法. dfs的时候,在递归节点v之前,要先预判断一下到达v之后总花费是否大于k,若大于K就跳过,不必再调用v节点,这样会省很多时间.对于路程的处理也同样

poj 2488 A Knight&#39;s Journey (DFS)

A Knight's Journey Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 34660   Accepted: 11827 Description Background The knight is getting bored of seeing the same black and white squares again and again and has decided to make a journey ar

LeetCode Subsets (DFS)

题意: 给一个集合,有n个互不相同的元素,求出所有的子集(包括空集,但是不能重复). 思路: DFS方法:由于集合中的元素是不可能出现相同的,所以不用解决相同的元素而导致重复统计. 1 class Solution { 2 public: 3 vector<vector<int>> subsets(vector<int>& nums) { 4 sort(nums.begin(),nums.end()); 5 DFS(0,nums,tmp); 6 return a