将正整数表示为三个数字的总和

问题描述

可以用多少种方式将正整数n表示为三个不同正整数之和。如果一个方法包含一个数字,而另一个方法则没有,那么这两种方法是不同的。

我设法获得了以下脚本,以将写n的方式的数量计为三个数字的总和,但这并没有考虑其他条件。

def nways(n):  
  
    if (n <= 2):  
        return False
    else:           
        ways = (n - 1) * (n - 2) / 2
          
    return ways

例如,如果n = 8,则我需要返回2,因为1 + 2 + 5 = 8和1 + 3 + 4 = 8,但是当前函数返回21 ...

背后的正确算法和数学是什么?

解决方法

解决方案

def nways(n):
    nways = 0
    for i in range(1,n-2):
        min_j,max_j = i+1,(n-i-1)//2
        nways += (max_j - min_j + 1) if max_j >= min_j else 0
    return nways

此算法消耗O(N)时间和O(1)空间。

说明

让我们将三个正数表示为ijk

由于它们都是不同的,因此这三个数字必须彼此大于或小于。我们假设最小的数字为i,中间的数字为j,最大的数字为k。因此关系将为i < j < k

n = 18为例

  • 我们从i = 1开始,然后j + k应该是17
    • 因此(j,k)可能从(2,12)(3,14),...到(8,9)
    • 通知(j,k)不能为(9,8)(10,7),因为j<k
    • 因此,min_j将是i+1(在这种情况下为2),max_j将是(n-i-1)//2(在这种情况下为8
    • (j,k)组合的数量为max_j - min_j + 1,在这种情况下为7
  • 我们继续i = 2,然后将j + k设为16
    • min_j将是i+1(在这种情况下为3),max_j将是(n-i-1)//2(在这种情况下为7
    • (j,k)组合的数量为max_j - min_j + 1,在这种情况下为5

我们尝试i的所有可能值,然后将(j,k)对的所有组合加起来,然后得出答案。

,

您可以使用蛮力,还有更多工作:

  • 检查三个术语是否不同
  • 存储一组唯一的条款
  • 那套衣服的长度就是你的结果
sourcetype

演示:https://repl.it/repls/ChocolateHelplessLivecd

,

一种非常不同的方法是使用约束求解器。这是一个示例:

import constraint as con

n = 8

p = con.Problem()
p.addVariables(['x','y','z'],range(1,n-2))
p.addConstraint(con.ExactSumConstraint(n))
p.addConstraint(lambda a,b,c : a < b < c,("x","y","z"))
sols = p.getSolutions()

print(len(sols))
sols

这给出了:

2
[{'x': 1,'y': 3,'z': 4},{'x': 1,'y': 2,'z': 5}]

我不知道预测溶液数量的简单公式。

,

您可以对@ hgb123已经很好的答案进行一些相当重要的优化,使其仍然使用蛮力,但是要更加聪明:

def ways(n):
  tuple_sum_set = set()

  for i in range(1,n-2):
    for j in range(i+1,n-2):
      for k in range(j+1,n-2):
        if i + j + k == n:
          tuple_sum_set.add((i,j,k))

  print(tuple_sum_set)
  return len(tuple_sum_set)

(如果您对此答案进行投票,请同时对@ hgb123的投票进行投票,因为这是他的答案的衍生形式)