【问题标题】:Matlab matrix with fixed sum over rows具有固定总和的Matlab矩阵
【发布时间】:2016-03-14 02:52:06
【问题描述】:

我正在尝试在 Matlab 中构建一个矩阵,其中行的总和是恒定的,但每个组合都被考虑在内。

例如,采用NxM matrix,其中M 是一个固定数字,N 将取决于K,这是所有行必须求和的结果。 例如,说K = 3M = 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的元素@

然而,这是非常低效的内存(尤其是对于较大的KM),但我想不出一个很好的方法来构造这个矩阵而不先构造总矩阵。

这可能以一种不错的方式实现吗?还是我应该使用一大堆 for 循环?

【问题讨论】:

  • 这是子集和问题的修改版本:en.wikipedia.org/wiki/Subset_sum_problem - 本质上,您试图确定给定整数子集的所有数字组合,这些组合给出一定的和。这是一个NP Complete 问题,对于KM 的大值没有有效的方法,除非您遍历所有可能的组合。顺便说一句,如果您确实想出了一个有效的算法,请告诉我。我们可以share a million dollars together

标签: matlab matrix


【解决方案1】:

这是一个使用动态编程的非常简单的版本。动态规划的基本思想是建立一个数据结构(这里是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}

【讨论】:

  • 所需循环的数量是否取决于M?还是代码通用?
  • 来晚了,我之前的评论没有回答你的问题。不,循环数不取决于 M。它总是 3 个循环。用于增加问题大小的外部之一,从 1 个元素开始,以缩进的元素数量结束。内部的两个循环将问题的较小实例的解决方案重新组合为新的解决方案。
  • @DGIB:再次阅读答案我意识到我浪费了很多性能来增加解决方案的大小(外循环)。相反,在每个步骤中将解决方案的大小加倍会产生更快的解决方案,但编码起来要困难得多。如果您正在使用大 M(我猜超过 40),那么改进代码可能是值得的。
【解决方案2】:

这可能比您的原始方法更有效,尽管它仍然会生成(然后丢弃)比需要更多的行。

M 表示列数,S 表示所需的总和。该问题可以解释为将长度为S 的区间划分为具有非负整数长度的M 子区间

这个想法是生成不是子区间长度,而是子区间边缘;并从中计算子区间长度。这可以通过以下步骤完成:

  1. 子区间边缘是M-1 整数值(不一定不同)在0S 之间。这些可以生成为Cartesian product,例如使用this answer

  2. 对区间边进行排序,并删除重复的边集。这就是该算法并非完全有效的原因:它会产生重复。但希望丢弃的暂定解决方案的数量会比您原来的方法少,因为这确实考虑了固定总和。

  3. 从边缘计算子区间长度。每个长度是两个连续边之间的差,包括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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-12
    • 2021-04-28
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多