15.Number Trapezium
http://acm.fzu.edu.cn/problem.php?pid=1020
难点在于判定路径重叠
思路:采用动态规划算法,自底向上进行运算。每次运算结果保存当前运算行的当前运算节点的左最大子路径和右最大子路径。任意两个相邻节点,对于它们的交叉路径(即左节点的右路径和右节点的左路径),判断二者是否有路径重叠,若是则保存两节点中较大节点的右(若大的为左节点)/左(若大的为右节点)子路径,删除另一个。
import sys
def max_sum(trapezium,n,m,k):
path={} # 保存每个节点左右两个最大和路径
max_line=n
while n>1:
n-=1
length=len(trapezium[n-1]) # 从倒数第二行开始
for i in range(0,length):
present=trapezium[n-1][i] # 当前节点的值
l_down=trapezium[n][i]
r_down=trapezium[n][i+1]
if n==max_line-1: #倒数第二行的长度为第一行的长度加上n-2
path[str([n-1,i])]={
'lmp':[present,l_down],
'rmp':[present,r_down]
}
else:
lmp=[present]
rmp=[present]
if sum(path[str([n,i])]['lmp'])==max(sum(path[str([n,i])]['lmp']),sum(path[str([n,i])]['rmp'])):
lmp.extend(path[str([n,i])]['lmp'])
else:
lmp.extend(path[str([n,i])]['rmp'])
if sum(path[str([n,i+1])]['lmp'])==max(sum(path[str([n,i+1])]['lmp']),sum(path[str([n,i+1])]['rmp'])):
rmp.extend(path[str([n,i+1])]['lmp'])
else:
rmp.extend(path[str([n,i+1])]['rmp'])
path[str([n-1,i])]={
'lmp':lmp,
'rmp':rmp
}
if i>0:# 从当前行的第二个节点开始判断路径是否重叠
# 路径重叠的情况只会发生在交叉路径上
p1=path[str([n-1,i-1])]['rmp']
p2=path[str([n-1,i])]['lmp']
if p1[1:]==p2[1:]:
if sum(p1)<sum(p2):
path[str([n-1,i-1])]['rmp']=[-9999]
else:
path[str([n-1,i])]['lmp']=[-9999]
if path[str([n-1,i-1])]['rmp']==[-9999] and path[str([n-1,i-1])]['lmp']==[-9999]:
path[str([n-1,i-1])]['rmp']=path[str([n-1,i-1])]['lmp']=[trapezium[n-1][i-1]]
sums=[] # 保留从第一行开始到最后一行的所有存在路径的各自的和
for i in range(0,m):
lmp=path[str([0,i])]['lmp']
rmp=path[str([0,i])]['rmp']
if len(lmp)==max_line:
sums.append(sum(lmp))
if len(rmp)==max_line:
sums.append(sum(rmp))
sums.sort()
print(sum(sums[-k:]))
line_left=0
while True:
read_in=sys.stdin.readline()
if not read_in:
break
if line_left==0:
N,M,K=tuple([int(x) for x in read_in.rstrip().split(' ')])
line_left=N
trapezium=[]
else:
trapezium.append([int(x) for x in read_in.rstrip().split('')])
line_left-=1
if line_left==0:
max_sum(trapezium,N,M,K)