2017省赛
题目描述
X 星球的流行宠物是青蛙,一般有两种颜色:白色和黑色。
X 星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去。
如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙。
∗WWWBBB
其中,W 字母表示白色青蛙,B 表示黑色青蛙,∗ 表示空杯子。
X 星的青蛙很有些癖好,它们只做 3 个动作之一:
跳到相邻的空杯子里。
隔着 1 只其它的青蛙(随便什么颜色)跳到空杯子里。
隔着 2 只其它的青蛙(随便什么颜色)跳到空杯子里。
对于上图的局面,只要 1 步,就可跳成下图局面:
WWW∗BBB
本题的任务就是已知初始局面,询问至少需要几步,才能跳成另一个目标局面。
输入描述
输入为 2 行,2 个串,表示初始局面和目标局面。我们约定,输入的串的长度不超过 15。
输出描述
输出要求为一个整数,表示至少需要多少步的青蛙跳。
输入输出样例
输入
*WWBB WWBB*
输出
2
题目大意
给出一些青蛙的起始分布状态A,和青蛙经过跳跃后的最终状态B,求出最少的跳跃次数。
最少跳跃次数,类似最小步数问题,可用BFS求解
思路:
无论怎么跳,空杯子只有一个,而且青蛙只会跳到空杯子里去。
计算所有青蛙的跳跃情况太麻烦,不如直接让空杯子跳,和原问题等价。
合法的跳跃情况
- 相邻位置跳跃
- 间隔一个位置跳跃
- 间隔两个位置跳跃
skip: [1,-1,2,-2,3,-3],六种跳跃情况,所以有六个分支
正数表示空杯子向右“跳跃”
负数表示空杯子向左“跳跃”
从起始状态开始BFS,过程中记录从起始转移到每个状态需要的跳跃步数
搜索到目标状态,即可停止,输出步数
去重:用set()记录所有的中间状态,搜索过程中,对于已经在set()中出现过的状态,不进入队列
代码:
from collections import deque
import sys
st = input() # 起始状态
ed = input() # 目标状态
all_st = set() # 记录所有状态的集合
q = deque()
skip = [1, -1, 2, -2, 3, -3] # 六种跳法
q.append([list(st), 0]) # 起点入队:状态和步数
all_st.add(st) # 加入起始状态
while len(q): # 队列不为空时
cst, cstep = q.popleft() # 取出当前状态和步数
for ne in skip: # 遍历所有的跳法
lcst = cst.copy() # 使用列表的深复制
p = lcst.index('*') # 找一下*的位置
np = p + ne # 空杯的下一个位置
if 0 <= np < len(cst): # 只能在这个范围内跳
lcst[p], lcst[np] = lcst[np], lcst[p] # 交换空杯和青蛙的位置
now_step = cstep + 1 # 步数+1
new_st = ''.join(lcst) # 将新状态转成字符串
if new_st == ed: # 如果新状态是目标状态
print(now_step) # 打印出当前步数
sys.exit(0) # 退出
# 判重
if new_st not in all_st: # 如果新状态不在集合里
all_st.add(new_st) # 加进去集合
q.append([lcst, now_step]) # 加入新状态