我需要找到数字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
但他们不包括数字重复的可能性。
答案 0 :(得分: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来临时存储排列。
答案 1 :(得分:2)
我通过递归找到了更好的方法,而且它更优雅优雅(我更喜欢优雅)并且比我以前的尝试更快( 0.00399705213秒在我的计算机上)
编辑:您需要我的自定义函数stretchmat.m,它会拉伸矢量以适合另一个矩阵的大小。有点像repmat但伸展第一个参数(详见帮助)。非常有用!
script.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个块来进行深度优先搜索。这可以像我上面那样以递归方式编写,有点类似于Merge Sort。 allcomb调用采用块大小(n)并找到将其分解为更小块的所有方法。
我们想要非零件,所以我们从1:n-1循环它。然后它将第一个块预先添加到第二个块的所有组合。通过仅对其中一个块进行所有梳理,我们可以确保所有解决方案都是唯一的。
至于排序,我不太清楚升序是什么意思。根据我的看法,您似乎按升序从最后一个数字中排序。你确定吗?任何种类都可以附加到script.m。
的末尾编辑2/3 备注
答案 2 :(得分:0)
首先在单元格数组中保存重复的所有组合。为此,请使用nmultichoosek。
v = 1 : 8;
combs = cell(length(v),0);
for i = v
combs{i} = nmultichoosek(v,i);
end
通过这种方式,combs
的每个元素都包含一个矩阵,其中每一行都是一个组合。例如,i-th
combs{4}
行是四个数字的组合。
现在你需要检查总和。要对所有组合执行此操作,请使用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秒内运行它。