动态规划:多边形游戏

大家好,我是连人。本期继续讨论动态规划的问题。

已知一个n边的多边形,在n个顶点上都有一个整数,在n条边上都存在‘+’或‘*’号。
在这里插入图片描述
游戏开始时,撤掉一条边。剩下的就会变成由n个顶点,n-1条边所组成的链条。
在这里插入图片描述
将其中两个相邻的顶点按之间的运算符进行运算,这两个顶点和这条边被替换为运算结果,链条被削减为n-1个顶点,n-2条边。如此反复直到最后只剩下一个点。
在这里插入图片描述
多边形游戏的目的是找到最大的最后一个点。

我们首先来分析链条,假设这是一条顶点数为n,边数为n-1的链条。取位置为s的边。这条边将链条分为了[0:s]和[s+1:n-1]两条链条。

链条最小值最大值
[0:s]ab
[s+1:n-1]cd

如果这条边是‘+’,那么问题就简单了,[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()

运行结果:
在这里插入图片描述
转载注明出处。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值