【问题标题】:Combinations of integers adding up to a specific number加起来为特定数字的整数组合
【发布时间】:2014-08-07 19:52:52
【问题描述】:

我需要一个程序来处理字母“01234”的所有组合,长度为 5,其中数字加起来不超过 4。

示例 00013, 00031, 00101, 10120

但不是 11213, 00341

问题:

  1. 如何计算加起来为 X 的字符串数?
  2. 如何生成所有加起来为 X 的字符串?
  3. 如何生成所有加起来为一个数字
  4. 这个概念在数学中叫什么? 更新:
  5. 如何找到与 X 相加的数字子集?

任何程序语言或伪代码都可以。通过概念,我的意思是找到将加起来等于给定总和的数字子集。所以,另外我想得到一个算法来找到这些子集。查找所有组合,然后过滤掉匹配的组合很容易,但对于较大的字母(数字字符串)来说,时间效率不高。

【问题讨论】:

  • 您可以使用五个嵌套的for 循环或一个Cartesian Product 来执行此操作。
  • @Edward 我已经有了生成所有组合的解决方案。我把它放在 Excel 中并过滤它。然后我有了解决方案,但不是一个灵活、高效的程序。
  • 一些谷歌搜索给了我“总和问题”、“同组问题”、“数硬币问题”和“背包问题”的概念。在我看来我的问题相当于一个大小为 4 和一组 {1,1,1,1,1,2,2,2,2,2,3,3,3,3, 3,4,4,4,4,4} 然而,背包问题被定义为找到一种有效的解决方案,而不是所有的解决方案!

标签: math combinations


【解决方案1】:

假设您想要总和为 4 的所有组合(看起来更像是您的问题的排列,因为您列出了 00013 和 00031),我认为首先您需要一个数字分区程序将总和 4 分成几部分,并且通过添加零将每个分区的长度扩展为 5,如下所示:

1, 1, 1, 1   ->    1, 1, 1, 1, 0
1, 1, 2      ->    1, 1, 2, 0, 0
1, 3         ->    1, 3, 0, 0, 0
2, 2         ->    2, 2, 0, 0, 0
4            ->    4, 0, 0, 0, 0

然后您可以对它们中的每一个进行排列。因为数字中有很多重复,所以排列的总数并没有那么大,比如1,1,1,1,0只有5个排列,11110,11101,11011,10111,01111。

关于如何进行数字分区,你可以查看here,至于排列,我是一个C++程序员,我会使用STL库中的next_permutation函数,或者查看here

这个方法非常通用,你可以处理任意和的组合而无需深循环。

【讨论】:

  • 优秀。数字分区是我一直在寻找的术语。一般来说,一旦您知道某物的名称,就很容易用 Google 搜索它。
【解决方案2】:

这是一个又快又脏的。我相信你会找到使它更有效的方法。该代码使用数组而不是字符串。

// Calculate sum of all digits
func numsum(a: [Int]) -> Int {
    return reduce(a, 0, { $0 + $1 })
}

// Maximum number allowed
let maxnum = 4

// Number of digits
let arlen = 5

// Number we are looking for
let reqnum = 4

// Array that holds the combinations
var a = Array(count: arlen, repeatedValue: 0)

// Array where we keep all positive results
var b = [[Int]]()

// Function to go over all combinations and storing those that add up to the number we are looking for
// Called recursively for each level starting with 0

func addNum(level: Int = 0) {
    if level == arlen {
        return
    }

    a[level] = 0
    while a[level] <= maxnum {
        //println(a)
        if numsum(a) == reqnum {
            b.append(a)
        }
        else {
            addNum(level: level + 1)
        }
        a[level] += 1
    }
}
// Calling the function
addNum()

// Printing it out so that it looks like strings
for arr in b {
    for n in arr {
        print(n)
    }
    println()
}

【讨论】:

  • 这是 SWIFT 编程语言吗?
【解决方案3】:

其他问答解决方案,在 Python 中

for a in range(5):
    for b in range(5):
        for c in range(5):
            for d in range(5):
                for e in range(5):
                    if a + b + c + d + e <= 4:
                        print a, b, c, d, e

您可以将&lt;= 替换为==,或将print 替换为N+= 1

有 70 个“重复排列”给出总和 4,126 个总和

【讨论】:

  • 感谢这个短代码。然而,我所说的概念是指找到一个集合中的数字加到一个特定的总和上的概念。仅使用这些子集时,编程效率会更高。
【解决方案4】:

(Composition) 是一个很好的起点。允许零会变得复杂(这需要考虑排序)。

虽然零会使它复杂化,但您可能必须在数学堆栈上询问才能获得通用公式,因为组合数学可能会变得相当棘手。否则,其他答案就足够了。

【讨论】:

    【解决方案5】:

    我相信递归代码简洁明了。它以字典顺序输出组合,没有多余的工作。

      procedure Combine(Digits, Sum, AMax: Integer; CurrentValue: string);
        if Digits = 0 then 
          output(CurrentValue)
        else
          for i := 0 to Min(Sum, AMax) do 
            Combine(Digits - 1, Sum - i, AMax, CurrentValue + IntToStr(i));
    
    //usage
      Combine(4, 3, 3, '');  
    

    输出:
    0000 0001 0002 0003 0010 0011 0012 0020 0021 0030 0100 0101 0102 0110 0111 0120 0200 0201 0210 0300 1000 1001 1002 1010 1011 1020 1100 1101 1110 1200 2000 2001年 2010 2100 3000

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-24
      • 2021-12-05
      • 1970-01-01
      相关资源
      最近更新 更多