【问题标题】:Iterating over all integer vectors summing up to a certain value in MATLAB?在MATLAB中迭代所有整数向量总和为某个值?
【发布时间】:2013-12-06 01:13:30
【问题描述】:

我想找到一种干净的方法,这样我就可以遍历所有长度为正整数的向量,比如n(称为x),这样sum(x) == 100在MATLAB中。

我知道这是一项指数级复杂的任务。如果长度足够小,比如 2-3,我可以通过 for 循环来完成(我知道它的效率很低)但是更长的向量呢?

提前致谢,

【问题讨论】:

  • 正如你所说,它是指数级的。如果您避免for 循环,您将一次生成所有向量,并且您很快就会遇到内存限制。
  • 它实际上不是指数的 - 缩放定律约为 n^k,因为 n 趋于无穷大,长度为 k 的向量总和为 n
  • @ChrisTaylor 是的,我的意思是向量长度的指数
  • 嗯,你可能是对的!
  • @PBM 当你说整数向量时,你到底是什么意思?是它们所有的元素都是整数还是整数?如果是前者,那么你将有无数种解决方案……如果是后者,那么它就是背包问题的变体,其复杂度为 O(n*sum)

标签: matlab vector


【解决方案1】:

这是一种使用递归的快速而肮脏的方法。这个想法是,要生成所有长度为k 且总和为n 的向量,首先为每个i=1..n 生成长度为k-1 的向量,总和为n-i,然后添加一个额外的i 到这些都结束了。

您可以通过在每个循环中预先分配 x 来加快速度。

注意输出的大小是(n + k - 1个选择n)行和k 列。

function x = genperms(n, k)

if k == 1
    x = n;
elseif n == 0
    x = zeros(1,k);
else
    x = zeros(0, k);
    for i = 0:n
        y = genperms(n-i,k-1);
        y(:,end+1) = i;
        x = [x; y];
    end
end

编辑

正如 cmets 中所提到的,这将遇到大型 nk 的内存问题。流式解决方案更可取,它一次生成一个输出。在像 Haskell 这样的非严格语言中,这非常简单 -

genperms n k
    | k == 1    = return [n]
    | n == 0    = return (replicate k 0)
    | otherwise = [i:y | i <- [0..n], y <- genperms (n-i) (k-1)]

即。

>> mapM_ print $ take 10 $ genperms 100 30
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,99]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,98]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,97]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,96]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,95]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,94]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,93]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,92]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,91]

几乎即时运行 - 无需担心内存问题。

在 Python 中,您可以使用生成器和 yield 关键字来实现几乎同样简单的事情。在 Matlab 中这当然是可能的,但我把翻译留给你!

【讨论】:

  • "quick" 绝对不是这个解决方案 :)
  • 哈哈。我的意思是“快速编写”而不是“快速运行” :) 当然有一些实现细节可以加快速度,但我认为没有更好的算法(这种方法生成解决问题所需的最少向量问题,而不是生成和拒绝算法,它会考虑比所需更多的向量)。
  • 它可能会遇到内存问题:)
  • 哦,当然。如果nk 很大,你需要做点别的。生成和拒绝算法将是最简单的,尽管速度很慢。我需要更加努力地想出一个有效地一次生成一个向量的解决方案(在非严格的语言中会容易得多!)。
【解决方案2】:

这是一次生成所有向量的一种可能方法(对于中等大小的n 会产生内存问题):

s = 10; %// desired sum
n = 3; %// number of digits
vectors = cell(1,n);
[vectors{:}] = ndgrid(0:s); %// I assume by "integer" you mean non-negative int
vectors = cell2mat(cellfun(@(c) reshape(c,1,[]), vectors, 'uni', 0).');
vectors = vectors(:,sum(vectors)==s); %// each column is a vector

现在您可以遍历这些向量:

for vector = vectors %// take one column at each iteration
    %// do stuff with the vector
end

为避免内存问题,最好根据需要生成每个向量,而不是一开始就生成所有向量。以下方法在一个for 循环中迭代所有可能的n-向量(不管n),拒绝总和不是所需值的那些向量:

s = 10; %// desired sum
n = 3;; %// number of digits
for number = 0: s^n-1
    vector = dec2base(number,s).'-'0'; %// column vector of n rows
    if sum(vector) ~= s
        continue %// reject that vector
    end
    %// do stuff with the vector
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-23
    相关资源
    最近更新 更多