【问题标题】:Simple Instructions Python Implementation简单指令 Python 实现
【发布时间】:2018-10-06 10:01:05
【问题描述】:

一个程序有一个寄存器X,初始化为0,只支持3条指令:

LDI v:将立即值 v 加载(存储)到 X ADD v:将立即值 v 加到 X 中,并将结果存储在 X 中。 SQR:将 X 的值平方并将结果存储在 X 中。

短指令序列如何影响 的值的示例:

Instruction     X
LDI 5           5
ADD 2           7
SQR             49
ADD -4          44
LDI -3          -3
SQR             9

我需要解决的问题是跳过选定的指令以在程序结束时为X 获取最大可能值。

到目前为止我所拥有的:

def prog(n):
    x = 0
    arr = []
    for i in range(n):
        itm = input().split()
        arr += [(itm)]
    #arr_rev = arr[::-1]    
    #limit = arr_rev.index(["SQR"])+len(arr)-1
    limit = len(arr) - 1 - arr[::-1].index(['SQR'])

    for i in range(len(arr)):
        if i < limit:
            if arr[i][0] == "ADD":
                x += int(arr[i][1])
            elif arr[i][0] == "LDI":
                x = int(arr[i][1])
            elif arr[i][0] == "SQR":
                x = x**2
        else:
            if arr[i][0] == "ADD" and int(arr[i][1]) > 0:
                x += int(arr[i][1])
            elif arr[i][0] == "LDI" and int(arr[i][1]) > x:
                x = int(arr[i][1])
            elif arr[i][0] == "SQR":
                x = x**2

    return x

因为我不想添加负数,所以我跳过那些。我也不想加载小于当前X 的数字。

但是,平方负数使其成为正数,因此上述策略可能不适用于所有情况。在我通过最后一个 SQR 之前,我在所有情况下都豁免了该规则。有没有更有效的方法来做到这一点?

【问题讨论】:

标签: python python-3.x algorithm performance


【解决方案1】:

如果“更有效率”是指“可能是正确的”,那么是的。您当前的代码不适用于所有输入。使用 SQR“通配符”,您无法轻易知道您正在查看的操作是否有益。比如

LDI  1
ADD -8
LDI  2
ADD -1
ADD  3
SQR

最大值来自(-8 + -1)^2。您应该使用动态编程(请参阅第一条评论中提供的链接)来跟踪每个步骤中所有“可能的最佳”结果。

您通常使用递归例程对此进行编程,该例程在考虑每条指令时尝试两个分支:在最终答案中使用/不使用该指令。然后你用X 的当前值和剩余的指令列表递归。


如果您想要进行数据流分析,您可以应用各种捷径。例如,在任何ADD 指令流中,您可以将所有负值和所有正值组合成一个ADD。当您拥有LDI 时,您会考虑新值在真实值和绝对值方面是否更大——后者是通过SQR 推动改进的原因。

坦率地说,我建议使用 bisect-recur-dynamic_programming 路线。


更新

我对此进行了更多思考。虽然 DP 是解决大问题的方法,但这不是你首先要攻击的(在我看来)。相反,解决是否包含每个特定命令的问题。您将需要同时执行这两项操作,直到进一步细化。你甚至不能保证你想要包含SQR 命令:后续的减法可能会使其不受欢迎。

递归的逻辑是这样的:

def optimize(x_reg, command_list):
    # x_reg          current value of the X register
    # command_list   remaining list of commands

    # base case
    if len(command_list) == 0
         return x_reg

    # recursion case
    op = command_list[0][0]
    if op == "ADD":
        new_x = x_reg + command_list[0][1]
    elif op == "LDI":
        new_x = command_list[0][1]
    else:    # op == "SQR":
        new_x = x_reg * x_reg

    with_op = optimize(new_x, command_list[1:])  # Use the command
    sans_op = optimize(x_reg, command_list[1:])  # Don't use the command

    return max(with_op, sans_op)    # Return the larger of the two solutions found

【讨论】:

  • 我在理解如何使用 DP 来解决问题时遇到了一些麻烦,但我阅读了一些关于 DP 的内容,它似乎非常强大并且是一种有趣的方法。
  • 在这种情况下,您将跟踪您为每个输入值组合获得的答案——这称为“记忆”。然后,如果一个递归分支让你得到一个你已经计算过的组合,你会在你的备忘录表中找到它并返回存储的值而不是重复计算。
  • 谢谢@Prune,你的实现很有效,我学到了很多。不过,这需要很长时间才能运行。如果我找到另一种运行速度更快的方法,我将与您分享。再次感谢
  • 是的,它很慢。鉴于您拥有的各种路径,随着您的程序变长,它会变得很多变得更糟。只有 6 条语句应该不会太慢,因为您只有 2^6 条路径可以尝试。您可以使用 DP 加快较长的案例,但问题本身并非微不足道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多