大家好,我是连人。本期继续讨论动态规划的问题。
已知一个n边的多边形,在n个顶点上都有一个整数,在n条边上都存在‘+’或‘*’号。
游戏开始时,撤掉一条边。剩下的就会变成由n个顶点,n-1条边所组成的链条。
将其中两个相邻的顶点按之间的运算符进行运算,这两个顶点和这条边被替换为运算结果,链条被削减为n-1个顶点,n-2条边。如此反复直到最后只剩下一个点。
多边形游戏的目的是找到最大的最后一个点。
我们首先来分析链条,假设这是一条顶点数为n,边数为n-1的链条。取位置为s的边。这条边将链条分为了[0:s]和[s+1:n-1]两条链条。
链条 | 最小值 | 最大值 |
---|---|---|
[0:s] | a | b |
[s+1:n-1] | c | d |
如果这条边是‘+’,那么问题就简单了,[0:n-1]的值一定在a+c到b+d之间。
如果这条边是‘*’,因为涉及到顶点含有负数的关系,所以只能将abcd两两
相乘,[0:n-1]的值是在min{ac,ad,bc,bd}和max{ac,ad,bc,bd}之间。
根据上面的分析,我们可以得知,多边形游戏也是有最优子结构的。
传统的做法是建立一个两层的二维数组m[ i ][ j ][ k ],代表以第i个点开头并且长为j的链条的最大值(k=1)和最小值(k=0)。
在最后寻找结果的时候只需要找m[ i ][ n ][ 1 ]中的最大值就可以了。
但是我不喜欢,写代码的时候太折腾人而且不易于维护。
我下面采用的这种在空间消耗上是略逊于传统做法的(多申请了两个长度为n的数组)。但是好懂啊。
将链条重新“摆直”,顶点从0计数到n-1,边从0计数到n-2。
在我的m[ i ][ j ]中,指代就不一样了。他的意思是位置从 i 到 j 的链条。因此最后的结果在m[0][n-1][1]里。
同样的,我们把老朋友摆上来,本次的方向接着按这种方向走。
m[ i ][ i ]就是自身,所以对角线直接写入对应值。
对于m[ i ][ j ],需要用s∈[i , j)进行遍历,找到最大值和最小值。
def min_max(i, s, j, m, edge):
a = m[i][s][0]
b = m[i][s][1]
c = m[s+1][j][0]
d = m[s+1][j][1]
if edge == '+':
return a+c, b+d
else:
e = [a*c, a*d, b*c, b*d]
minf = e[0]
maxf = e[0]
for k in range(1, 4):
if minf > e[k]:
minf = e[k]
if maxf < e[k]:
maxf = e[k]
return minf, maxf
def poly_max(n, m, edge):
for r in range(1, n):
for i in range(0, n - r):
j = i + r
for s in range(i, j):
minf, maxf = min_max(i, s, j, m, edge[s])
if m[i][j][0] > minf:
m[i][j][0] = minf
if m[i][j][1] < maxf:
m[i][j][1] = maxf
return m[0][n-1][1]
if __name__ == '__main__':
n = int(input("一共有几条边:"))
edge = []
vertex = []
for i in range(0, n):
v = int(input("第" + str(i) + "个点值为:"))
vertex.append(v)
e = input("第" + str(i) + "个运算符为:")
edge.append(e)
interrupt = int(input("删掉边的序号:"))
new_vertex = vertex[interrupt+1:n] + vertex[0:interrupt+1]
new_edge = edge[interrupt+1:n] + edge[0:interrupt]
m = []
for i in range(0, n):
m.append([])
for j in range(0, n):
if i == j:
m[i].append([new_vertex[i], new_vertex[i]])
else:
m[i].append([0, 0])
print(poly_max(n, m, new_edge))
print(vertex)
print(new_vertex)
print(edge)
print(new_edge)
for i in range(0, n):
for j in range(0, n):
print(m[i][j][0], end='\t')
print()
print()
for i in range(0, n):
for j in range(0, n):
print(m[i][j][1], end='\t')
print()
运行结果:
转载注明出处。