简体   繁体   English

将一个正整数表示为三个数字之和

[英]Representing an positive integer as a sum of three numbers

In how many ways the positive integer n can be represented as the sum of three different positive integers.正整数n可以用多少种方式表示为三个不同正整数的和。 The two methods are different if one contains a number that the other does not.如果一种方法包含另一个不包含的数字,则这两种方法是不同的。

I've managed to get the following script to count the number of ways to write n as a sum of three numbers, but it's not takin the other condition in consiredation.我已经设法获得以下脚本来计算将n写为三个数字之和的方法的数量,但它并没有考虑其他条件。

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

For example if n = 8 I would need to return 2 since 1 + 2 + 5 = 8 and 1 + 3 + 4 = 8, but the current function returns 21...例如,如果 n = 8 我需要返回 2,因为 1 + 2 + 5 = 8 和 1 + 3 + 4 = 8,但当前函数返回 21...

What would be the correct algorithm and math behind this?这背后的正确算法和数学是什么?

Solution解决方案

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

This algorithm consumes O(N) time and O(1) space.该算法消耗O(N)时间和O(1)空间。

Explanation解释

Let's denote the three positive numbers as i , j , k .让我们将三个正数表示为i , j , k

And since they are all different, these three numbers must be greater than or smaller than each other.而且由于它们都不同,因此这三个数字必须大于或小于彼此。 We assume the smallest number to be i , the middle one to be j , the largest to be k .我们假设最小的数字是i ,中间的数字是j ,最大的数字是k So then the relation would be i < j < k .那么关系将是i < j < k

Take n = 18 for examplen = 18为例

  • we start from i = 1 , then j + k should be 17 .我们从i = 1开始,那么j + k应该是17
    • So (j,k) could be from (2,12) , (3,14) , ... to (8,9) .所以(j,k)可以从(2,12) , (3,14) , ... 到(8,9)
    • Notice (j,k) couldn't be (9,8) , (10,7) because j<k注意(j,k)不能是(9,8) , (10,7)因为j<k
    • Therefore min_j would be i+1 (in this case 2 ), max_j would be (ni-1)//2 (in this case 8 )因此min_j将是i+1 (在这种情况下2 ), max_j将是(ni-1)//2 (在这种情况下8
    • Number of (j, k) combinations are max_j - min_j + 1 which is 7 pairs in this case (j, k)组合的数量是max_j - min_j + 1 ,在这种情况下是7
  • we go on with i = 2 , then j + k should be 16 .我们继续i = 2 ,那么j + k应该是16
    • min_j would be i+1 (in this case 3 ), max_j would be (ni-1)//2 (in this case 7 ) min_j将是i+1 (在这种情况下3 ), max_j将是(ni-1)//2 (在这种情况下7
    • Number of (j, k) combinations are max_j - min_j + 1 which is 5 pairs in this case (j, k)组合的数量是max_j - min_j + 1 ,在这种情况下是5

We try all the possible values of i then add up all the combinations of (j, k) pair, then we get the answer.我们尝试i所有可能值,然后将(j, k)对的所有组合相加,然后我们得到答案。

You could use brute-force, with some more works:你可以使用蛮力,还有一些工作:

  • check if three terms is different检查三个术语是否不同
  • store a set of unique terms存储一组独特的术语
  • the length of that set is your result那组的长度是你的结果
def ways(n):
  tuple_sum_set = set()

  for i in range(1, n+1):
    for j in range(1, n+1):
      for k in range(1, n+1):
        if i + j + k == n and len(set([i, j, k])) == 3:
          tuple_sum_set.add(tuple(sorted([i,j,k])))

  print(tuple_sum_set)
  return len(tuple_sum_set)

print(ways(8))

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

A very different approach would be to use a constraint solver.一种非常不同的方法是使用约束求解器。 Here is an example:下面是一个例子:

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

This gives:这给出:

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

I am not aware of a simple formula that predicts the number of solutions.我不知道预测解决方案数量的简单公式。

You can make some pretty significant optimizations to @hgb123's already great answer to still use brute-force, but be a little more clever about it:您可以对@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)

(If you up-vote this answer, please up-vote @hgb123's as well as this is a derivative of his answer) (如果您对这个答案投赞成票,请投给@hgb123 以及这是他的回答的衍生物)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM