总和为总和的组合

时间:2014-02-01 16:28:01

标签: matlab combinations permutation

如何生成一个矩阵,其中所有可能的数字组合总和为重复的总和?

基本上,x1x2x3的组合使x1 + x2 + x3 = n

例如:n =3

0 1 2 
0 2 1
1 0 2
1 2 0
1 1 1

使用预定义的Matlab函数有没有简单的方法呢?

我试过

n=6;
nchoosek(0:n,3)

给了我

 0     1     2
 0     1     3
 0     1     4
 0     1     5
 0     1     6
 0     2     3
 0     2     4
 0     2     5
 0     2     6
 0     3     4
 0     3     5
 0     3     6
 0     4     5
 0     4     6
 0     5     6
 1     2     3
 1     2     4
 1     2     5
 1     2     6
 1     3     4
 1     3     5
 1     3     6
 1     4     5
 1     4     6
 1     5     6
 2     3     4
 2     3     5
 2     3     6
 2     4     5
 2     4     6
 2     5     6
 3     4     5
 3     4     6
 3     5     6
 4     5     6

如何提取总数等于n的所有行? 我认为线性索引或find应该可以实现,但我不知道如何去做。

此致

5 个答案:

答案 0 :(得分:7)

具体来说,让我们看看你的3个值加起来为6的例子。这样做的标准方法是考虑将2个'分隔符'放入一行6个相同的'对象'中:那些分隔符然后划分对象分为3组,你可以读出每组的长度。所以我们需要做的就是列举放置这些分隔线的所有方法。您可以使用nchoosek(1:8, 2):通过描述2 + 6 == 8个对象+分隔符中2个分隔符的位置,该矩阵的每一行描述一个除法。

这比枚举0-6的所有三元组然后挑选那些增加正确总数的方法更有效。

我真的不会说MATLAB,所以以下内容可能是单一的(并且欢迎提出改进它的建议!),但这样的事情应该有效:

% Total we're aiming for.                                                             
n = 6;                                                                                
% Number of pieces to divide that total into.                                         
k = 3;                                                                                
% All possible placements of internal dividers.                                       
dividers = nchoosek(1:(n+k-1), k-1);                                                  
ndividers = size(dividers, 1);                                                        
% Add dividers at the beginning and end.                                              
b = cat(2, zeros(ndividers, 1), dividers, (n+k)*ones(ndividers, 1));                  
% Find distances between dividers.                                                    
c = diff(b, 1, 2) - 1

以下是this site提供的结果:

c =

   0   0   6
   0   1   5
   0   2   4
   0   3   3
   0   4   2
   0   5   1
   0   6   0
   1   0   5
   1   1   4
   1   2   3
   1   3   2
   1   4   1
   1   5   0
   2   0   4
   2   1   3
   2   2   2
   2   3   1
   2   4   0
   3   0   3
   3   1   2
   3   2   1
   3   3   0
   4   0   2
   4   1   1
   4   2   0
   5   0   1
   5   1   0
   6   0   0

答案 1 :(得分:1)

使用dec2base生成重复的所有组合,logical indexing仅保留具有所需总和的组合:

n = 6;
m = 3;
c = dec2base(0:(n+1)^m-1,n+1,m)-'0'; %// generate combinations with repetition
result = c(sum(c,2)==n,:); %// keep those with desired sum. Logical indexing

答案 2 :(得分:0)

我相信您正在描述restricted integer partitions的排列,尽管您的示例似乎并不完整。对于n = 3到元素{0,1,2}的三个部分,有两个解:{0,1,2}和{1,1,1}。这些可以进一步加入:

{{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}, {1, 1, 1}}

如果这不是您想要的,您应该澄清为什么不包括这些额外的排序。

如果这种理解是正确的,您应该能够通过搜索该短语找到许多资源。一些例子:

Elegant Python code for Integer Partitioning

Integer Partition in Java

Algorithm for generating integer partitions

Integer Partition Algorithm by Jerome Kelleher

Integer Partition Algorithm by Daniel Scocco

Fast Algorithms for Generating Integer Partitions(PDF)(看起来很重要)

Stony Brook Algorithm Repository - Partitions

作为一个实际例子,使用 Mathematica 会写:

IntegerPartitions[6, {3}, Range[0, 5]]

输出:

{{5, 1, 0}, {4, 2, 0}, {4, 1, 1}, {3, 3, 0}, {3, 2, 1}, {2, 2, 2}}

这些可以随后被置换以产生其他排序。

通过从所有数字< = n 开始设置递归函数以生成这些分区非常容易,然后附加< =不超过名词的。这一直持续到每个列表的长度为 p ;如果列表总计n则保留;如果没有,它就会被丢弃。再次,在 Mathematica

f[n_, p_, c__] /; Length@{c} == p := If[+c == n, {{c}}, {}]
f[n_, p_, c___] := Array[f[n, p, c, #] &, Min[c, n - +c] + 1, 0, Join]

f[6, 3]

输出:

{{2, 2, 2}, {3, 2, 1}, {3, 3, 0}, {4, 1, 1}, {4, 2, 0}, {5, 1, 0}, {6, 0, 0}}

答案 3 :(得分:0)

函数nchoosek提供了在总和中选择r-1加号的可能方法。例如,x1 + x2 + x3 = 5,则必须在和1 + 1 + 1 + 1 + 1 = 5上选择两个信号。对于非负解,使变换yi = x1 + 1,并求解y1 + y2 +。 .. = m + n

nchoosek的结果提供了加号的位置。

程序的剩余部分提供所选信号之间的总和。

clear all    
close all    
clc    

% Program that generates the possible distributions
% M objects in r boxes 
% Éderson D'Martin Costa    
% 12/02/2015    

% number of objects
m = 3;    

% number of boxes    
r = 3;

% total number of possibilities
% C = nchoosek(m+r-1,r-1)

v = 1:m+r-1;    
C = nchoosek(v,r-1);    
[l,c] = size(C);    
Y = zeros(l,c+1);    
Y(:,1) = C(:,1);    
Y(:,end) = m+r-C(:,end);

for i = r-1:-1:2    
    Y(:,i) = C(:,i)-C(:,i-1);    
end    

X = Y-1;    
display(X)    
% sum(X,2)

答案 4 :(得分:0)

正如@Mark Dickinson指出的那样。我只想给出直观的解释。

您的问题可以重申为“您可以将3个苹果分配给3个人的方式有多少种?”

假设你有3个人:AA,BB,CC,你想在其中分发3个苹果。你怎么能这样做?

AA   |    BB     | CC
***  |           | 
*    |     *     | *
**   |     *     | 
........
* -> represent apples.

现在,如果您认为问题只是在5个职位中选择两个|,我们知道可以使用5选择2.