この問題は、バックトラッキングを使用して解決できます。任意の行の三角形の各要素に対してこれを行うには、現在の要素と次の行の3つの接続された隣接要素の合計の最大値を決定する必要があります。
if elem = triangle[row][col] and the next row is triangle[row+1]
then backtrack_elem = max([elem + i for i in connected_neighbors of col in row])
まず、決定する方法を見つけてくださいconnected_neighbors of col in row
位置(row、col)の要素の場合、row=nextの接続されたネイバーが[next[col-1],next[col],next[col+1]]
提供さcol - 1 >=0
れcol+1 < len(next)
ます。これがサンプル実装です
>>> def neigh(n,sz):
return [i for i in (n-1,n,n+1) if 0<=i<sz]
これにより、接続されているネイバーのインデックスが返されます。
今、私たちは次のように書くことができbacktrack_elem = max([elem + i for i in connected_neighbors of col in row])
ます
triangle[row][i] = max([elem + next[n] for n in neigh(i,len(next))])
三角形を行方向に反復し、currが任意の行であり、iが行のi番目の列インデックスである場合、次のように記述できます。
curr[i]=max(next[n]+e for n in neigh(i,len(next)))
ここで、現在の行と次の行を一緒に読み取って三角形を繰り返す必要があります。これは次のように行うことができます
for (curr,next) in zip(triangle[-2::-1],triangle[::-1]):
次に、enumerateを使用して、インデックスのタプルと要素自体を生成します
for (i,e) in enumerate(curr):
それから一緒にクラブをします
>>> for (curr,next) in zip(triangle[-2::-1],triangle[::-1]):
for (i,e) in enumerate(curr):
curr[i]=max(next[n]+e for n in neigh(i,len(next)))
ただし、上記の操作は破壊的であり、元の三角形のコピーを作成して作業する必要があります
route = triangle # This will not work, because in python copy is done by reference
route = triangle[:] #This will also not work, because triangle is a list of list
#and individual list would be copied with reference
したがって、deepcopy
モジュールを使用する必要があります
import copy
route = copy.deepcopy(triangle) #This will work
トラバースを次のように書き直します
>>> for (curr,next) in zip(route[-2::-1],route[::-1]):
for (i,e) in enumerate(curr):
curr[i]=max(next[n]+e for n in neigh(i,len(next)))
最終的に、すべての要素が可能な限り最高のルートコストを提供する別の三角形になります。実際のルートを取得するには、元の三角形を使用して逆算する必要があります
したがって、インデックスの要素の[row,col]
場合、最も高いルートコストはroute[row][col]です。最大ルートに従う場合、次の要素は接続されたネイバーであり、ルートコストはroute [row] [col]-orig[row][col]である必要があります。行ごとに繰り返すと、次のように書くことができます。
i=[x for x in neigh(next,i) if x == curr[i]-orig[i]][0]
orig[i]
そして、ピーク要素から始めて下向きにループする必要があります。したがって、
>>> for (curr,next,orig) in zip(route,route[1:],triangle):
print orig[i],
i=[x for x in neigh(i,len(next)) if next[x] == curr[i]-orig[i]][0]
あなたの例は簡単すぎて解決できないので、少し複雑な例を見てみましょう
>>> triangle=[
[3],
[7, 4],
[2, 4, 6],
[8, 5, 9, 3],
[15,10,2, 7, 8]
]
>>> route=copy.deepcopy(triangle) # Create a Copy
ルートの生成
>>> for (curr,next) in zip(route[-2::-1],route[::-1]):
for (i,e) in enumerate(curr):
curr[i]=max(next[n]+e for n in neigh(i,len(next)))
>>> route
[[37], [34, 31], [25, 27, 26], [23, 20, 19, 11], [15, 10, 2, 7, 8]]
最後にルートを計算します
>>> def enroute(triangle):
route=copy.deepcopy(triangle) # Create a Copy
# Generating the Route
for (curr,next) in zip(route[-2::-1],route[::-1]): #Read the curr and next row
for (i,e) in enumerate(curr):
#Backtrack calculation
curr[i]=max(next[n]+e for n in neigh(i,len(next)))
path=[] #Start with the peak elem
for (curr,next,orig) in zip(route,route[1:],triangle): #Read the curr, next and orig row
path.append(orig[i])
i=[x for x in neigh(i,len(next)) if next[x] == curr[i]-orig[i]][0]
path.append(triangle[-1][i]) #Don't forget the last row which
return (route[0],path)
三角形をテストするには、
>>> enroute(triangle)
([37], [3, 7, 4, 8, 15])
jamylakのコメントを読んで、この問題はオイラー18に似ていることに気付きましたが、違いは表現です。オイラー18の問題はピラミッドを考慮していますが、この質問の問題は直角三角形です。彼のコメントに対する私の返事を読むことができるので、私は結果が異なる理由を説明しました。それでも、この問題はオイラー18で動作するように簡単に移植できます。これが移植です
>>> def enroute(triangle,neigh=lambda n,sz:[i for i in (n-1,n,n+1) if 0<=i<sz]):
route=copy.deepcopy(triangle) # Create a Copy
# Generating the Route
for (curr,next) in zip(route[-2::-1],route[::-1]): #Read the curr and next row
for (i,e) in enumerate(curr):
#Backtrack calculation
curr[i]=max(next[n]+e for n in neigh(i,len(next)))
path=[] #Start with the peak elem
for (curr,next,orig) in zip(route,route[1:],triangle): #Read the curr, next and orig row
path.append(orig[i])
i=[x for x in neigh(i,len(next)) if next[x] == curr[i]-orig[i]][0]
path.append(triangle[-1][i]) #Don't forget the last row which
return (route[0],path)
>>> enroute(t1) # For Right angle triangle
([1116], [75, 64, 82, 87, 82, 75, 77, 65, 41, 72, 71, 70, 91, 66, 98])
>>> enroute(t1,neigh=lambda n,sz:[i for i in (n,n+1) if i<sz]) # For a Pyramid
([1074], [75, 64, 82, 87, 82, 75, 73, 28, 83, 32, 91, 78, 58, 73, 93])
>>>