问题描述
有9只盘子,排成1个圆圈。
其中8只盘子内装着8只蚱蜢,有一个是空盘。
我们把这些蚱蜢顺时针编号为 1~8
每只蚱蜢都可以跳到相邻的空盘中,
也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。
请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,
并且保持空盘的位置不变(也就是1-8换位,2-7换位,…),至少要经过多少次跳跃?
思考与分析
给出结论: 对于从某一状态转换到另一状态,问最少需要多少步, 不出意外都是广搜。
广搜的优势在于:第一次遍历到的结果,一定就是最短路径或最少步数,特殊类型题除外。
接下来考虑本题
首先, 将盘子们看做一个一维数组, 通过取余的方式使他们逻辑上相连。
接下来,构造队列,将盘子的初始状态入队,分四种情况(+1, +2 , -1 , -2 )进行广搜, 将得到的结果判重后入队。
判重的原因是:有可能搜索到相同排列顺序的盘子们, 因此要定义判重数组, 或使用mep容器去重。
蓝桥杯的广搜题真的挺少的, 不过套模板一般都能很轻松的解出来。
#include<bits/stdc++.h>
using namespace std;
int s = 123456789, t = 876543219;
int dir[4] = {
-2, -1, 1, 2}, a[10];
bool index[1000000000]; //判断情况是否重复
int num(int a[]) {
//数组转变量
int sum = 0;
for(int i = 0; i < 9; i++) {
sum *= 10; sum += a[i];
}
return sum;
}
void bfs() {
queue<int>q_index; //记录位置情况
queue<int>q_step; //记录步数
//队列初始化
index[s] = 1;
q_index.push(s);
q_step.push(1);
int flag = 0;
while(flag != 1) {
int x = q_index.front(); //出队操作
int cnt = q_step.front();
int k = 8, temp;
while(x>0) {
if(x%10==9) temp=k; //记下空盘的位置
a[k--] = x%10;
x /= 10;
}
for(int i = 0; i < 4; i++) {
swap(a[temp], a[(temp+dir[i]+9)%9]); //位置移动
int j = num(a);
if(!index[j]) {
if(j==t) {
cout<<cnt<<'\n'; flag=1; }
index[j] = 1;
q_index.push(j);
q_step.push(cnt+1);
}
swap(a[temp], a[(temp+dir[i]+9)%9]); //空盘一共需要跳四次,因此交换后还需换回来
}
q_index.pop();
q_step.pop();
}
}
int main() {
bfs();
return 0; }
求三连 求三连! 啊!我第一个给博主三连!