题目描述
如图所示: 有9只盘子,排成1个圆圈。其中8只盘子内装着8只蚱蜢,有一个是空盘。
在这里插入图片描述
我们把这些蚱蜢顺时针编号为 1~8。每只蚱蜢都可以跳到相邻的空盘中,也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。
请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,并且保持空盘的位置不变(也就是1-8换位,2-7换位,…),至少要经过多少次跳跃?
【总结】
1.一看就知道是宽搜的题目。bfs必然用到队列queue和set
2.首先:我们这样想,蚱蜢有很多,有各种各样的跳法,但是蚱蜢跳就相当于是空盘子在跳,就相当于要考虑盘子是怎么跳的,而考虑盘子的跳法就大大的减小了我们的思考难度。3.盘子的跳法:左1格、左2格、右1格、右2格
4.存储时需要存储状态+level以及要防止重复状态
思路:
求最短步数的搜索,可以采用广度优先搜索。
用'912345678'字符串表示初始状态,用'987654321'表示目标状态,其中'9'表示可以跳过去的空位置。每次与'9'相邻左右(环形)两个位置与其交换,产生下一个搜索状态;若是新状态,记录步数,加入搜索队列,否则丢弃。
对于搜索状态是否已经出现过以及步数,C++和java中可用map来记录,python中可以用字典来记录。
from collections import deque
mp = {} # 字典标记状态是否已存在,{'字符串',对应最短步数}
que = deque() # 队列,用于实现广度优先搜索
if __name__ == '__main__':
a1 = '912345678' #用9表示空位置
a2 = '987654321'
que.append(a1)
mp[a1] = 0
f = 0
while len(que) != 0:
t = que.popleft() # 字符串
t0 = list(t) # 列表
x = mp[t]
i = t.index('9')
for j in range(-2, 3): # 从队列首状态开始搜索。'9'与左右相邻2个位置依次交换,产生新状态
i0 = divmod(i+j+9, 9)[1]
t0[i], t0[i0] = t0[i0], t0[i] # 交换元素
tmp = ''.join(t0) # 列表转为字符串
if tmp not in mp: # 插入新状态
mp[tmp] = x + 1
que.append(tmp)
if tmp == a2:
f = 1
break
t0[i], t0[i0] = t0[i0], t0[i] # 交换回来
if f == 1:
break
print(mp[a2])
常规c++解法:
#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再模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;
}