【问题标题】:Combination of lists with a specific sum具有特定总和的列表组合
【发布时间】:2017-07-03 23:18:12
【问题描述】:

我想用python解决这个问题:

按数字顺序取数字 1、2、3 到 9 并加上一个加号 数字之间的符号或减号或两者都不是,以求和 加起来为 100。例如,实现此目的的一种方法是:1 + 2 + 34 - 5 + 67 - 8 + 9 = 100,它使用六个优点和缺点。你需要做的最少的优点和缺点是多少?

我考虑过从生成有效元组开始,例如(1,2,34,567,89),然后计算出哪些加起来等于 100,然后找到最短的。

为此,我首先创建了一个可能的数字列表,十位和百位,因为我很确定没有 4 位数字的组合。

strnumbers = [str(x) for x in range(1,10)]
digits = [int(i) for i in strnumbers]
tens = [int(strnumbers[a] + strnumbers[a+1]) for a in range(8)]
hundreds = [int(strnumbers[a] + strnumbers[a+1] + strnumbers[a+2]) for a in range(7)]

但是,我不确定如何创建实际可能的列表。

我的问题有两个:

  1. 您将如何使用十位和百位数字创建可能的元组?

  2. 就计算而言,这是一种合理的方法吗?感觉我在创造很多额外的工作

【问题讨论】:

  • 这些问题太多了。一个好主意是看看itertoolsitertools.product
  • 你有没有想过使用eval?这样,您可以创建一个字符串并插入运算符,而不是生成数字列表。
  • @yinnonsanders 好的,这会减少上面的列表,但是如何创建解决方案?
  • @Ev.Kounis 如果我删除问题的第 2 部分,那还不错吧?我看过 itertools,但没有什么特别合适的 - 我需要做一个笛卡尔积,然后过滤掉任何重复的数字
  • 假设您使用eval,问题就简化为创建以下形式的字符串:"1 op1 2 op2 3 op3 4 op4 5 op5 6 op6 7 op7 8 op8 9" 其中 opN 代表 @ 987654326@、+ 或空字符串。这个问题确实可以通过itertools.product 解决。

标签: python permutation


【解决方案1】:
import itertools

results = []
for opers in itertools.product(('-','+',''),repeat=8):
    expression = '1{}2{}3{}4{}5{}6{}7{}8{}9'.format(*opers)
    result = eval(expression)
    if result == 100:
        results.append(expression)
best_result = min(results, key=len)
print(best_result, len(best_result)-9)

【讨论】:

  • (我首先发布了一个更复杂的解决方案,然后注意到 Rory Daulton 的回答中有一个很好的提示,这大大缩短了它)
  • 非常好。我也没有看到更新的格式,所以这真的很有帮助。
  • 感谢我的工作。请注意,此代码实际上并未回答原始问题,即“您需要执行此操作的最少正负数是多少?”您遗漏了我的步骤 6 和 7,它们得到了最终所需的数字。
【解决方案2】:

这是一种方法,我用它来解决类似的问题。您没有显示足够的代码让我展示我的完整解决方案,所以这是一个想法大纲。这种方法与您的方法不同,但您不必担心每个术语的位数。

  1. 您希望数字按顺序排列,其中包含一些其他字符,因此请考虑字符串 '1{}2{}3{}4{}5{}6{}7{}8{}9'
  2. 使用itertools.product() 获得用'+''-''' 填充这些大括号的所有可能方法。你需要八个这样的短字符串。产品总数为3**8 == 6561,这对于 Python 程序来说是一个很小的数字。
  3. 对于每个可能的产品,使用产品上字符串的format() 方法创建一个完整的表达式。
  4. 使用eval() 计算该表达式的值。使用eval() 通常很危险,但由于您只在自己构造的字符串上使用它,所以没有问题。
  5. 将该值与100 进行比较并存储产生该值的字符串。
  6. 收集所有字符串后,找到长度最短的字符串。那个人的优点和缺点最少。
  7. 从最短的长度中减去9 的位数,打印出来,就大功告成了。

步骤 5 到 7 可以组合使用,从而减少内存使用量。使用product 作为生成器并对其进行循环,而不是从中创建列表,也可以降低内存使用率。

【讨论】:

    【解决方案3】:

    我会以不同的方式处理这个问题。你有你的数字列表:

    digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    因此,对于如何连接数字,您必须做出 8 个决定(或者 9,如果允许在 1 之前放一个减号,但我认为它不在这里)。对于这些决定中的每一个,您都有三个选择:加、减或都不选择(加入)。因此有 3^8 种选择。我会迭代它们以找到最好的:

    from itertools import product
    
    digits = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    options = ["", "+", "-"]
    number = 100
    best_sol_str = ""
    best_sol_cost = 10  # Or infinity
    for sol in product(*([options] * 8)):  # `* 9` if starting with "-" allowed
        factor = 1
        current = 0
        total = 0
        sol_cost = 0
        sol_str = ""
        # Remove `("",) + ` if used `* 9` before
        for opt, d in zip(("",) + sol, digits):  
            sol_str += opt + str(d)
            if opt == "":
                current = current * 10 + d
            else:
                total += factor * current
                current = d
                sol_cost += 1
                if opt == "+":
                    factor = 1
                elif opt == "-":
                    factor = -1
        total += factor * current
        if total == number and sol_cost < best_sol_cost:
            best_sol_str = sol_str
            best_sol_cost = sol_cost
    
    print("Best solution: {}={} ({} operations).".format(
        best_sol_str, number, best_sol_cost))
    

    【讨论】:

      猜你喜欢
      • 2016-04-28
      • 1970-01-01
      • 1970-01-01
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多