原题链接及参考资料:
# http://poj.org/problem?id=3009 # https://exp-blog.com/algorithm/poj/poj3009-curling-2.0/
一 注意事项
1 初始时刻的运动状态为“静止”,接下来有4种运动方向:上下左右
3 当状态为运动时,下一步进行判断:
3.1 继续运动
3.2 遇到石头,则停止,并击碎石头
3.3 遇到终点,停止运动,不击碎,返回
2 由于寻找具有最小路径的一种方案,因此设置一种参数,用于比较每一方案的路径大小,并且更新其值为最小路径数(在本程序中,该参数是self.MaxStep)。
3 提前设置下一步的坐标更新列表:
# 首先定义移动的方向
dir = {0:[-1,0],1:[0,-1],2:[1,0],3:[0,1]}
# North:0,West:1,South:2,East:3
二 代码实现
# http://poj.org/problem?id=3009
# https://exp-blog.com/algorithm/poj/poj3009-curling-2.0/
import collections
# 将数据转化为索引,并返回新数据、字典、起始点和终止点
def sub2cor(subData,hh,ww):
data_dict = collections.defaultdict(list)
temp = []
count = 0
for i in range(hh):
# 注意每行数据之间有空格,需要处理空格
res = subData[i].split(' ')
for j in range(ww):
if res[j] == '2':
# 确定为起始点
start = str(i)+";"+str(j)
# 修改元素值为0
res[j] = '0'
elif res[j] == '3':
target = str(i)+";"+str(j)
# 添加到字典中
temp.append(res[j])
data_dict[str(i)+";"+str(j)] = [count,res[j]]
count +=1
return temp,data_dict,start,target
class Solution:
def DFS(self,s,target):
# 获得键值
self.keys = data_dict.keys();
# # 最大步数
self.MaxStep = 11
# # 总步数
# self.steps = 0
# 开始执行吧
self.dfs(s,False,0,0,False)#起始节点+静止+方向为0+计数为0+不击碎石头(特别注意:初始时刻的状态为静止,而不是运动)
return self.MaxStep
def dfs(self,s,Status,face,step,RmStone):# s表示当前节点的坐标,Status:表示当前状态,True为运动,False为静止,face:表示运动的方向,step:用于记录步数,Rmstone:表示是否移除石头,True移除
# 获取当前节点的坐标
hh,ww = map(int,s.split(";"))
# 判断是否等于目标点
if s == target:
if step< self.MaxStep: #直到找到具有最短路径的一种方案
self.MaxStep=step
return
# 当需要击碎石头时
if RmStone:# 当击碎石头时,修改当前方向下的下一步格子的元素值,将其变为‘0’
# 修改数据中的元素信息
stone_hh = dir[face][0] + hh;
stone_ww = dir[face][1] + ww;
new_str = str(stone_hh) + ";" + str(stone_ww) #获得当前方向下的下一步格子的坐标
data_dict[new_str][1] = '0'
# 当前状态为静止时,接下来就要移动了(有4种运动方向),并且不再击碎石头
if Status == False: #当前状态为静止
# 有东西南北4个节点可以走
for i in range(4):
# 下一个节点的坐标
stone_hh = dir[i][0] + hh;
stone_ww = dir[i][1] + ww;
new_str = str(stone_hh) + ";" + str(stone_ww)
# 判断是否在已知键值中,并且元素值不为1
if new_str in self.keys:
if data_dict[new_str][1] != '1':
# 此时可以运动了
self.dfs(new_str,True,i,step+1,False) #新坐标,运动,方向沿i,步数+1,不击碎石头
elif Status == True: #当前状态为移动
# 接下来的状态有:1 继续运动 2 遇到石头,则停止,并击碎石头 3 遇到终点,停止运动,不击碎,返回
stone_hh = dir[face][0] + hh;
stone_ww = dir[face][1] + ww;
new_str = str(stone_hh) + ";" + str(stone_ww)
if new_str in self.keys:
if data_dict[new_str][1] == '0': # 下一位置为0且不越界,继续运动
self.dfs(new_str, True, face, step, False) # 继续运动时,step不更新
elif data_dict[new_str][1] == '1': # 下一位置为1且不越界,停止运动,并消除下一位置的石头
self.dfs(s, False, face, step, True) # 停止运动时,不更新坐标;击碎石头时,step不更新
elif data_dict[new_str][1] == '3': # 下一位置为3且不越界,运动到位置3后停止运动,游戏结束
self.dfs(new_str, False, face, step, False)
else: # 如果越界,则返回
return
# if new_str in self.keys and data_dict[new_str][1] == '0': #下一位置为0且不越界,继续运动
# self.dfs(new_str,True,face,step,False) #继续运动时,step不更新
# elif new_str in self.keys and data_dict[new_str][1] == '1': #下一位置为1且不越界,停止运动,并消除下一位置的石头
# self.dfs(s,False,face,step,True) #停止运动时,不更新坐标;击碎石头时,step不更新
# elif new_str in self.keys and data_dict[new_str][1] == '3': #下一位置为3且不越界,运动到位置3后停止运动,游戏结束
# self.dfs(new_str, False, face, step, False)
# else: # 如果都不满足,则返回到上一步的静止状态,然后去更新4个运动方向
# return
# 如果执行到这里还未结束,说明4个方向的路均不通,需要返回上一次迭代 # 回溯前还原石头,即还原上一步的棋盘状态
if RmStone:
stone_hh = dir[face][0] + hh;
stone_ww = dir[face][1] + ww;
new_str = str(stone_hh) + ";" + str(stone_ww)
data_dict[new_str][1] = '1'
return
## 迎接输入
data = [] #注意,读入的数据为字符型,而不是整形(除非自己转化)
data_size = []
#
while True:
W,H = map(int,input().strip().split(' '))
if W==0 and H==0:
break
else:
data_size.append([W,H])
temp = []
for i in range(H):
temp.append(input().strip())
data.append(temp)
# print(data)
# print(data_size)
#
## 也应该考虑索引转坐标吧
# 首先定义移动的方向
dir = {0:[-1,0],1:[0,-1],2:[1,0],3:[0,1]}
# North:0,West:1,South:2,East:3
# 组数n
n = len(data_size)
# 初始化最大步数
MaxStepss = 11
# 分别对每组数据进行处理
for i in range(n):
# 获取当前数据及数据大小
subData = data[i]
ww,hh = data_size[i][0],data_size[i][1]
# 将数据转化为索引,并返回新数据、字典、起始点和终止点
subData,data_dict,s,target = sub2cor(subData,hh,ww)
# print(subData,data_dict,s,target)
# 开始处理
test = Solution()
ans = test.DFS(s,target)
if ans < MaxStepss:
print(ans)
else:
print("-1")
输入:
2 1
3 2
6 6
1 0 0 2 1 0
1 1 0 0 0 0
0 0 0 0 0 3
0 0 0 0 0 0
1 0 0 0 0 1
0 1 1 1 1 1
6 1
1 1 2 1 1 3
6 1
1 0 2 1 1 3
12 1
2 0 1 1 1 1 1 1 1 1 1 3
13 1
2 0 1 1 1 1 1 1 1 1 1 1 3
0 0
输出:
1
4
-1
4
10
-1