【问题标题】:All possible combinations such that sum of all numbers is a fixed number所有可能的组合,使得所有数字的总和是一个固定数字
【发布时间】:2015-04-16 05:56:54
【问题描述】:

我需要找到所有可能的数字 1:8 组合,使得所有元素的总和等于 8 组合需要按升序排列。

例如

1 7

2 2 4

1 3 5

1 2 2 3

1 1 1 1 1 1 1 1

一个数字可以重复。但是组合一定不能.. 即 1 2 2 3 和 2 1 2 3 我需要升序的解决方案所以每个组合只有一种可能性

我在Find vector elements that sum up to specific number in MATLAB上尝试了一些在线建议的代码

   VEC = [1:8];
      NUM = 8;
      n = length(VEC);
      finans = zeros(2^n-1,NUM);
      for i = 1:(2^n - 1)
        ndx = dec2bin(i,n) == '1';
        if sum(VEC(ndx)) == NUM
        l = length(VEC(ndx));
        VEC(ndx)
        end
      end

但它们不包括数字重复的可能性。

【问题讨论】:

  • 作为一个起点,我会尝试把它变成一个矢量问题。您提到您可能有重复值,那么如何将数字组合视为 8 维向量。第一个分量是 1 的个数,第二个分量是 2 的个数,依此类推。所以集合 1, 1, 1, 2, 3 将是 因为它有三个 1、一个 2 和一个三。这种解决问题的方法会有所帮助,因为会有一些几何方式来思考问题,以避免必须计算所有可能性。
  • 当然,有一个很重要的问题:您只是想找到加起来为 8 的值吗?或者您是否正在尝试编写一个程序,以便无论他们要求您使用什么数字,您都可以运行您的程序并生成正确的结果。
  • 另外,如果@CortAmmon 对问题的回答是后者,那么数字列表有哪些限制?他们会一直积极吗?它们是否总是包含给定范围内的所有整数?
  • 如果second answer 正确,OP 可以接受吗?如果没有,请告诉我如何解决!

标签: matlab


【解决方案1】:

我通过递归找到了一种更好的方法,它比我之前的尝试(在我的计算机上0.00399705213 秒)更优雅(我喜欢优雅)和更快。

编辑:您将需要我的自定义函数 stretchmat.m 来拉伸向量以适应另一个矩阵的大小。有点像 repmat 但拉伸第一个参数(有关详细信息,请参阅帮助)。很有用!

脚本.m

% Define funciton to prepend a cell x with a variable i
cellprepend = @(x,i) {[i x]};

% Execute and time function
tic;
a = allcomb(cellprepend,1,8);   % Solution in a
toc;

allcomb.m

function a = allcomb( cellprepend, m, n )
    % Add entire block as a combination
    a{1} = n;

    % Exit recursion if block size 1
    if n == 1
        return;
    end

    % Recurse cutting blocks at different segments
    for i = m:n/2
        b = allcomb(cellprepend,i,n-i);
        a = [a cellfun( cellprepend, b, num2cell( stretchmat( i, b ) ) )];
    end
end

所以这个想法很简单,因为添加到 8 的解决方案是详尽无遗的。如果您只寻找有效的答案,您可以通过将问题分成 2 个块来进行深度优先搜索。这可以像我上面那样递归地编写,有点类似于合并排序。 allcomb 调用获取块大小 (n) 并找到将其分解为更小块的所有方法。

我们想要非零片段,所以我们从 1:n-1 循环它。然后它将第一个块添加到第二个块的所有组合之前。通过只对其中一个块进行所有梳理,我们可以确保所有解决方案都是唯一的。

至于排序,我不太清楚你所说的升序是什么意思。据我所知,您似乎是从最后一个数字按升序排序。你可否确认?任何排序都可以附加到 script.m 的末尾。

编辑 2/3 备注

  • 对于置换唯一的情况,代码可以找到here
  • 感谢 @Simon 帮助我多次对代码进行质量检查

【讨论】:

  • 未定义函数或变量stretchmat.
  • @Simon 抱歉,我刚刚添加了一个指向我的自定义函数拉伸垫的链接。它太有用了,我忘记了不是每个人都有它;)
  • 实际上 OP 指定它:“一个数字可以重复,但组合不能重复,即 1 2 2 3 和 2 1 2 3”。我正在比较时间只是因为我在另一个答案中与您的解决方案内存不足,并且我对计算时间感到好奇:D
  • @Simon 我明白你的意思,这很容易做到。我不会因为这个答案而改变它,因为它是 OT 并且有点混乱。然而,这样做应该像将循环线更改为for i = max( m, p ):min( n / 2, q ) 一样简单,其中 p 和 q 是您所需范围的下限和上限。然后通过递归函数将其作为参数提供。
  • 感谢您与我合作!我希望如果它得到支持,我可以以某种方式分享代表。回家后我也会更新我电脑上的性能。
【解决方案2】:

编辑:看看我的second more efficient answer

天真的方法!哪里可以找到 cartprod.m 函数here

% Create all permutations
p(1:8) = {0:8};
M = fliplr( cartprod( p{:} ) );

% Check sums
r = sum( M, 2 ) == 8;
M = M(sum( M, 2 ) == 8,:);   % Solution here

肯定有比这更有效的解决方案,但如果您只需要一个快速而肮脏的解决方案来处理小排列,这将起作用。请注意,这使得 Matlab 需要 3.5 GB 的 RAM 来临时存储排列。


【讨论】:

    【解决方案3】:

    首先将所有带有重复的组合保存在一个元胞数组中。为此,只需使用nmultichoosek

    v = 1 : 8;
    combs = cell(length(v),0);
    for i = v
        combs{i} = nmultichoosek(v,i);
    end
    

    这样,combs 的每个元素都包含一个矩阵,其中每一行都是一个组合。例如,combs{4}i-th 行是四个数字的组合。

    现在您需要检查总和。为了对所有组合执行此操作,请使用cellfun

    sums = cellfun(@(x)sum(x,2),combs,'UniformOutput',false);
    

    sums 包含所有组合之和的向量。为了 例如,sums{4} 具有组合 combs{4} 的数字之和。

    下一步是检查固定金额。

    fixed_sum = 10;
    indices = cellfun(@(x)x==fixed_sum,sums,'UniformOutput',false);
    

    indices 包含逻辑值数组,判断组合是否满足固定和。例如,indices{4}(1) 会告诉您第一个 4 个数字的组合是否等于 fixed_sum

    最后,检索一个新元胞数组中的所有有效组合,同时对它们进行排序。

    valid_combs = cell(length(v),0);
    for i = v
        idx = indices{i};
        c = combs{i};
        valid_combs{i} = sortrows(c(idx,:));
    end
    

    valid_combs 是一个类似于combs 的单元格,但只有组合的总和等于您的期望值,并按使用的数字数量排序:valid_combs{1} 具有所有有效组合与 1 个数字 valid_combs{2}有2个数字,依此类推。另外,感谢sortrows,同样数量的组合也会被排序。例如,如果fixed_sum = 10 那么valid_combs{8}

     1     1     1     1     1     1     1     3
     1     1     1     1     1     1     2     2
    

    这段代码非常高效,在我非常旧的笔记本电脑上我可以在 0.016947 秒内运行它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      相关资源
      最近更新 更多