洛谷 P10578 [蓝桥杯 2024 国 A] 旋转九宫格

洛谷 P10578 [蓝桥杯 2024 国 A] 旋转九宫格

此题解对arcmiao的解释,转载证明

题目内容

P10578 [蓝桥杯 2024 国 A] 旋转九宫格

题目描述

给定一个 \(3\times 3\) 的九宫格,每个格子内分别含有一个数字,每个格子里的数字互不相同。每步我们可以选择任意一个 \(2\times 2\) 的区域将其顺时针旋转,例如:
例如

1 2 3
4 5 6
7 8 9

将其旋转右上角,可得:

1 5 2
4 6 3
7 8 9

问最少需要几步才能将给定的状态旋转为

1 2 3
4 5 6
7 8 9

输入格式

输入的第一行包含一个整数 \(T\) 表示询问的组数。
接下来依次输入每组询问。
每组询问包含三行,每行包含三个数,表示询问的九宫格的状态。

输出格式

输出 \(T\) 行,每行包含一个整数表示本次询问的答案。

输入输出样例 #1

输入 #1

2
1 2 3
4 5 6
7 8 9
1 5 2
4 6 3
7 8 9

输出 #1

0
3

说明/提示

对于 \(60\%\) 的评测用例,\(T=1\);
对于所有评测用例,\(T\le 10^5\)


题意

题意很简洁,在一个 \(3\times3\) 的九宫格 中,可以任意选择 \(2\times2\) 的区域顺时针旋转,问你最少多少次旋转后九宫格成为:

1 2 3
4 5 6
7 8 9


算法建议

这题我建议使用BFS,我来举个例子:假如你的眼镜掉到地上了,那你肯定会向四周去摸索(BFS),如果你有一个球,掉到了地上,而且你知道方向,这时肯定会向着一个方向一直找(DFS)。而且,就算使用DFS,也会超时我被挂了一下午

算法思路

首先,用一个9个字符字符串量记录一下解,如果使用二维来记录的话大概率要超时,所以不如压缩成一维的字符串。
但是这样还是可能超时,还需要使用 map 进行离散(也可能是我不会优化)。

接着就是DFS函数部分,先开一个队列,把标准的答案 123456789 入队列,然后重复模拟旋转,判断当前状态是否被访问过,,若新状态没有被访问,就把当前旋转次数加一如果达到目标,就停止,否则继续入队列搜索。采用逆推的办法,速度更快。


代码

arcmiao的代码几乎一样,主要看注释。

#include <bits/stdc++.h>
using namespace std;
string str="123456789";//题目要求的答案,也就是标准 。 
map<string,int>h;//记录每个状态达到标准需要的最小步数。 
queue<string>q;
int t;
void bfs(){
    q.push(str);
    h[str]=1;
    while(q.size()){
	    string s=q.front();
	    q.pop();
	   string v[4]={s,s,s,s};//这里的 s  代表的不是字符 s,而是 s 字符串。 
		v[0][0]=s[1];v[0][4]=s[3];
		v[0][1]=s[4];v[0][3]=s[0];
//左上角区域逆时针旋转 
//v[0][0]=s[1];		位置0 ←位置1的值 
//v[0][4]=s[3];		位置1 ←位置4的值 
//v[0][1]=s[4];		位置4 ←位置0的值 
//v[0][3]=s[0];		位置4 ←位置3的值 

		v[1][1]=s[2];v[1][5]=s[4];//右上角区域逆时针旋转 
		v[1][2]=s[5];v[1][4]=s[1];
		
		v[2][3]=s[4];v[2][6]=s[3];//左下角区域逆时针旋转 
		v[2][4]=s[7];v[2][7]=s[6];
		
		v[3][4]=s[5];v[3][7]=s[4];//右下角区域逆时针旋转 
		v[3][5]=s[8];v[3][8]=s[7];
		//因为这里是逆推,所以要逆时针旋转。 
		for(int i=0;i<4;i++) {
		    if (!h[v[i]]){//判断新状态是否被访问过 
			    h[v[i]]=h[s]+1;
			    if (v[i]==str) break;//如果回到标注就可以停了,也算是优化。 
			    q.push(v[i]);
			}
		}
	}
}
int main(){
    cin>>t;
    bfs();
    while(t--){
	    string s;
	    for (int i=0;i<9;i++) {
		    char c;
		    cin>>c;
		    s+=c;//把读取到的字符拼接到一起,字符 c 会读取换行。 
		}
	    cout<<h[s]-1<<endl;//减一是因为初始状态记为一 
	}
    return 0;
}

望审核大大通过。
如果对你有帮助,点个赞再走吧,谢谢!

posted @ 2025-08-07 10:56  sunhy2012  阅读(12)  评论(0)    收藏  举报