1.问题描述
设有一个三角形的数塔,顶点结点称为根结点,每个结点有一个整数数值。从顶点出发,可以向左走,也可以向右走。如图10一1所示。
问题:当三角形数塔给出之后,找出一条从第一层到达底层的路径,使路径的值最大。若这样的路径存在多条,任意给出一条即可。
旋转一下就跟马拦卒过河题目一样了(x轴为层数,y轴为该点在该层中的序号),只能往下或右走
对最底层的顶点分类讨论一下各求出最大路径值(因此使用动态规划比单纯递推好很多,不然重复计算好多次子问题)即可
解法1 递推解法
#递推解法
#输入一个坐标,返回到达它的最大路径
#递推假设:能够计算F(x-1,y) F(x,y-1)的最大路径,及其路径长度
def F(x,y):
global triangle
if x==0 and y==0:
return ([(0,0)],triangle[(0,0)])
if x==0:
routine1,len1=F(x,y-1)
a=routine1.copy()
a.append((x,y))
return a,len1+triangle[(x,y)]
if y==0:
routine1,len1=F(x-1,y)
a=routine1.copy()
a.append((x,y))
return a,len1+triangle[(x,y)]
routine1,len1=F(x-1,y)
routine2,len2=F(x,y-1)
if len1>len2:
a=routine1.copy()
a.append((x,y))
return a,len1+triangle[(x,y)]
else:
a=routine2.copy()
a.append((x,y))
return a,len2+triangle[(x,y)]
解法2 动态规划 记忆化搜索
#动态规划 记忆化搜索
#递推版,添加一个用于存储的全局变量,递推基础改成记忆搜索,返回前把结果保存到全局变量即可
routine={(0,0):([(0,0)],triangle[0,0])}
def F2(x,y):
global triangle,routine
if (x,y) in routine:
return routine[(x,y)]
if x==0:
routine1,len1=F(x,y-1)
a=routine1.copy()
a.append((x,y))
routine[(x,y)]=(a,len1+triangle[(x,y)])
return routine[(x,y)]
if y==0:
routine1,len1=F(x-1,y)
a=routine1.copy()
a.append((x,y))
routine[(x,y)]=(a,len1+triangle[(x,y)])
return routine[(x,y)]
routine1,len1=F(x-1,y)
routine2,len2=F(x,y-1)
if len1>len2:
a=routine1.copy()
a.append((x,y))
routine[(x,y)]=a,len1+triangle[(x,y)]
return routine[(x,y)]
else:
a=routine2.copy()
a.append((x,y))
routine[(x,y)]=a,len2+triangle[(x,y)]
return routine[(x,y)]
解法3 动态规划 从子问题求母问题
#动态规划,非记忆化搜索非递推,从子问题求母问题
#二维的,还是按对角线来求的顺序
def F3(x,y):
global triangle
r={(0,0):([(0,0)],triangle[0,0])}
if x==0 and y==0:
return r[(0,0)]
for i in range(1,x+y):
temp1,temp2=r[(i-1,0)]
temp1=temp1.copy()
temp1.append((x,y))
r[(i,0)]=(temp1,temp2+triangle[(i,0)])
temp1,temp2=r[(0,i-1)]
temp1=temp1.copy()
temp1.append((x,y))
r[(0,i)]=(temp1,temp2+triangle[(0,i)])
for j in range(1,i):
temp1,temp2=r[(i-j,j-1)]
temp3,temp4=r[(i-j-1,j)]
if temp2>temp4:
temp1=temp1.copy()
temp1.append((i-j,j))
r[(i-j,j)]=(temp1,temp2+triangle[(i-j,j)])
else:
temp3=temp3.copy()
temp3.append((i-j,j))
r[(i-j,j)]=(temp3,temp4+triangle[(i-j,j)])
if x==0:
temp1,temp2=r[(x,y-1)]
temp1=temp1.copy()
temp1.append((x,y))
return (temp1,temp2+triangle[(x,y)])
if y==0:
temp1,temp2=r[(x-1,y)]
temp1=temp1.copy()
temp1.append((x,y))
return (temp1,temp2+triangle[(x,y)])
temp1,temp2=r[(x,y-1)]
temp3,temp4=r[(x-1,y)]
if temp2>temp4:
temp1=temp1.copy()
temp1.append((x,y))
return temp1,temp2+triangle[(x,y)]
else:
temp3=temp3.copy()
temp3.append((x,y))
return temp3,temp4+triangle[(x,y)]
测试代码
import re
triangle={}
def initialize():
global triangle
s=input("从上到下,从左到右输入值:\n")
s=re.findall('\d+',s)
i=0 #x+y值
j=0
for t in s:
triangle[(i-j,j)]=int(t)
j+=1
if j>i:
i+=1
j=0
return i-1
t=initialize()
#递推解法
#输入一个坐标,返回到达它的最大路径
#递推假设:能够计算F(x-1,y) F(x,y-1)的最大路径,及其路径长度
def F(x,y):
global triangle
if x==0 and y==0:
return ([(0,0)],triangle[(0,0)])
if x==0:
routine1,len1=F(x,y-1)
a=routine1.copy()
a.append((x,y))
return a,len1+triangle[(x,y)]
if y==0:
routine1,len1=F(x-1,y)
a=routine1.copy()
a.append((x,y))
return a,len1+triangle[(x,y)]
routine1,len1=F(x-1,y)
routine2,len2=F(x,y-1)
if len1>len2:
a=routine1.copy()
a.append((x,y))
return a,len1+triangle[(x,y)]
else:
a=routine2.copy()
a.append((x,y))
return a,len2+triangle[(x,y)]
#动态规划 记忆化搜索
#递推版,添加一个用于存储的全局变量,递推基础改成记忆搜索,返回前把结果保存到全局变量即可
routine={(0,0):([(0,0)],triangle[0,0])}
def F2(x,y):
global triangle,routine
if (x,y) in routine:
return routine[(x,y)]
if x==0:
routine1,len1=F(x,y-1)
a=routine1.copy()
a.append((x,y))
routine[(x,y)]=(a,len1+triangle[(x,y)])
return routine[(x,y)]
if y==0:
routine1,len1=F(x-1,y)
a=routine1.copy()
a.append((x,y))
routine[(x,y)]=(a,len1+triangle[(x,y)])
return routine[(x,y)]
routine1,len1=F(x-1,y)
routine2,len2=F(x,y-1)
if len1>len2:
a=routine1.copy()
a.append((x,y))
routine[(x,y)]=a,len1+triangle[(x,y)]
return routine[(x,y)]
else:
a=routine2.copy()
a.append((x,y))
routine[(x,y)]=a,len2+triangle[(x,y)]
return routine[(x,y)]
def test(t,F):
len=triangle[(0,0)]
routine=[(0,0)]
for i in range(t+1):
temp1,temp2=F(i,t-i)
if temp2>len:
len=temp2
routine=temp1
print("max routine:\n{}\nmax lenth:{}".format(routine,len))
return routine,len
test(t,F)
test(t,F2)
test(t,F3)
测试结果如下