我正在尝试在Matlab中构建一个矩阵,其中行的总和是不变的,但每个组合都被考虑在内。
例如,取一个NxM matrix
,其中M
是固定数字,N
取决于K
,所有行必须求和的结果。
例如,说K = 3
和M = 3
,这将给出矩阵:
[1,1,1
2,1,0
2,0,1
1,2,0
1,0,2
0,2,1
0,1,2
3,0,0
0,3,0
0,0,3]
目前,我首先创建所有可能组合的矩阵,而不考虑总和(例如,这也包含[2,2,1]和[3,3,3])然后扔掉和不等于K
然而,这是非常低效的内存(特别是对于较大的K
和M
),但我没想到在没有首先构造总矩阵的情况下构造这个矩阵的好方法。
这可能是一个很好的方式吗?或者我应该使用一大堆for循环?
答案 0 :(得分:3)
这是一个使用动态编程的非常简单的版本。动态编程的基本思想是建立一个数据结构(这里是S
),它保存同一问题的较小实例的中间结果。
M=3;
K=3;
%S(k+1,m) will hold the intermediate result for k and m
S=cell(K+1,M);
%Initialisation, for M=1 there is only a trivial solution using one number.
S(:,1)=num2cell(0:K);
for iM=2:M
for temporary_k=0:K
for new_element=0:temporary_k
h=S{temporary_k-new_element+1,iM-1};
h(:,end+1)=new_element;
S{temporary_k+1,iM}=[S{temporary_k+1,iM};h];
end
end
end
final_result=S{K+1,M}
答案 1 :(得分:1)
这可能比原始方法更有效,尽管它仍会生成(然后丢弃)比所需更多的行。
让M
表示列数,S
表示所需的总和。该问题可以解释为将长度为S
的区间划分为具有非负整数长度的M
子区间。
想法是生成而不是子区间长度,但是子区间边;从那些计算子区间长度。这可以通过以下步骤完成:
M-1
和0
之间的子区间边是S
个整数值(不一定不同)。这些可以使用例如Cartesian product生成为this answer。
对间隔边进行排序,并删除重复的边集。这就是为什么算法不是完全有效的原因:它产生重复。但希望丢弃的暂定解决方案的数量将少于原始方法,因为这确实考虑了固定金额。
从边缘计算子区间长度。每个长度是两个连续边之间的差异,包括0
处的固定初始边缘和S
处的最终边缘。
代码:
%// Data
S = 3; %// desired sum
M = 3; %// number of pieces
%// Step 1 (adapted from linked answer):
combs = cell(1,M-1);
[combs{end:-1:1}] = ndgrid(0:S);
combs = cat(M+1, combs{:});
combs = reshape(combs,[],M-1);
%// Step 2
combs = unique(sort(combs,2), 'rows');
%// Step 3
combs = [zeros(size(combs,1),1) combs repmat(S, size(combs,1),1)]
result = diff(combs,[],2);
结果以lexicographical order排序。在您的示例中,
result =
0 0 3
0 1 2
0 2 1
0 3 0
1 0 2
1 1 1
1 2 0
2 0 1
2 1 0
3 0 0