题目:跳蚱蜢
如图所示:
有9只盘子,排成1个圆圈。
其中8只盘子内装着8只蚱蜢,有一个是空盘。
我们把这些蚱蜢顺时针编号为 1~8
每只蚱蜢都可以跳到相邻的空盘中,
也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。
请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,
并且保持空盘的位置不变(也就是1-8换位,2-7换位,…),至少要经过多少次跳跃?
注意:要求提交的是一个整数,请不要填写任何多余内容或说明文字。
分析思路:
给9只盘子编号,用一维数组保存蚱蜢状态,一维数组的下标即盘子编号,每个数组元素存蚱蜢编号,元素值为0表示空盘。
于是蚱蜢初态为012345678,目标态为087654321。
因为空盘的左边第一个、第二个蚱蜢和右边的第一个、第二个蚱蜢可以往里跳,所以得出结论:1种状态通过一步变换可以衍生出4种状态。
解题关键已很明显,就是解决如何表示出空盘左一、左二、右一、右二的蚱蜢跳进空盘。经过以上设定和分析,蚱蜢跳进空盘相当于数组中0和其左一、左二、右一、右二元素交换位置,要实现这一操作,就需要获知0的的下标。结合盘子环形摆放的特点,令0的下标为pos,那么和0做交换的元素的下标可表示为(pos+1+9)%9,(pos+2+9)%9,(pos-1+9)%9,(pos-2+9)%9。(加9可防止下标溢出,可自行验证)
题解代码如下:(添加了额外计算程序运行时间的代码,可视需求增删)
#include<iostream>
#include<queue>
#include<set>
#include<string>
#include<time.h>//必须加后缀
using namespace std;
struct record{//用于记录变换状态
string state;//记录各盘数字
int step;//记录是第几步
int pos;//用于记录空盘的位置(下标)
record(string State,int Step,int Pos)
{
state=State;
step=Step;
pos=Pos;
}
record(){}
void operator=(const record &rec)
{
state=rec.state;
step=rec.step;
pos=rec.pos;
}
};
// //string作为内置数据类型,有默认比较规则,也可以不写
// struct cmpSet{//自定义比较规则
// bool operator()(string s1,string s2)
// {
// return s1<s2;//不取等以排除重复状态
// }
// };
string Origin="012345678";//初态
string Target="087654321";//目标态
queue<record> q;//保存搜索记录
set<string> st;//保存状态,使用默认比较规则
//set<string,cmpRecord>;//自定义了比较规则的写法
void add(string state,int step,int pos,int new_pos)
{
swap(state[pos],state[new_pos]);
if(st.find(state)==st.end()){//查重
q.push(record(state,step+1,new_pos));
st.insert(state);
}
}
int main()
{
clock_t start,finish;//记录开始,结束时刻
double totaltime;//保存运行时间
start=clock();//获取开始时间
q.push(record(Origin,0,0));//加入初态
st.insert(Origin);
record rec;
while(!q.empty())
{
rec=q.front();//取出队首元素
if(rec.state==Target){//到达目标状态
cout<<rec.step<<endl;//输出答案
break;//跳出循环
}
//加9防止下标溢出
add(rec.state,rec.step,rec.pos,(rec.pos+1+9)%9);//左一蚱蜢跳进空盘
add(rec.state,rec.step,rec.pos,(rec.pos+2+9)%9);//左二蚱蜢跳进空盘
add(rec.state,rec.step,rec.pos,(rec.pos-1+9)%9);//右一蚱蜢跳进空盘
add(rec.state,rec.step,rec.pos,(rec.pos-2+9)%9);//右二蚱蜢跳进空盘
q.pop();//队首出队
}
finish=clock();//获取结束时间
totaltime=(double)(finish-start);//计算运行时间
cout<<"The runtime is "<<totaltime<<"ms."<<endl;//输出运行时间
return 0;
}
答案为20。运行结果如下。
总结:该题要点为宽搜BFS、环形数据的处理。