又一次暴力求解被羞辱,这个题感觉一定可以for循环代替递归,然而经验值不足(智商感人的委婉说法😢)没能在放弃之前想出来,于是再次拿来主义:
class YetAnotherRobotSimulation:
def getMaximumProbability(self,L,x,y):
px = tuple(x)
py = tuple(y)
tl = len(px)
'''
tp = []
for i in range(0, tl):
tp.append((px[i],py[i]))
'''
tp = {}
for i in range(0, tl):
tp[(px[i],py[i])] = True
c = []
# 一张屌炸天的排列组合速查表;生成它需要一点数学推导:
# C(4,2) = C(3,1) + C(3,2)
# 这里隐含了DP思想,知道了C(3,1)和C(3,2)这两种组合数,
# 那么现在新加入一个元素,在4个元素里面挑出2个,无非是:
# 要么用新的元素和原来所有1个元素的组合组成新的2元组,
# 要么不选这个新的,直接用原来3个里面已有的2元组
for i in range(0, 51):
c.append([])
for j in range(0, i+1):
if j == 0:
c[i].append(1)
else:
if j > i-1:
c[i].append(c[i-1][j-1])
else:
c[i].append(c[i-1][j-1]+c[i-1][j])
m = 0
u = r = l = d = 0
# 只要按顺序列举出所有的指令seq组合即可,
# 指令之间的排序根本不影响最终结果
for u in range(0, L+1):
for r in range(0, L-u+1):
for l in range(0, L-u-r+1):
d = L-u-r-l
s = 0
pu = pr = pl = pd = 0
# 由于指令顺序不重要,
# 那么只要枚举出每种指令可能生效的次数即可
for pu in range(0,u+1):
for pr in range(0,r+1):
for pl in range(0,l+1):
for pd in range(0,d+1):
# 这是一个小优化,事先准备好目标集合字典:m
# 比在运行中不断用in来判断要快很多(1/4)
#if (pr-pl, pu-pd) in tp:
if tp.get((pr-pl, pu-pd), False):
# 虽然生效指令的个数决定了最终到达的位置
# 但是我们还是需要知道有多少种组合方式
# 因为要算概率,需要知道当前指令序列能有
# 多少种方式到达这里,所有能够到达目标
# 集合的方式除以某个指令序列可能的所有
# 生效形式(1<<L)就是它的到达目标概率
s += c[u][pu]*c[r][pr]*c[l][pl]*c[d][pd]
m = max(s, m)
return float(m)/(1<<L)