我想找到一个干净的方法,以便我可以迭代所有长度正整数的向量,比如n
(称为x
),这样在MATLAB中sum(x) == 100
我知道这是一项指数级复杂的任务。如果长度足够小,比方说2-3我可以通过for
循环(我知道这是非常低效的)来实现它,但是更长的向量怎么样?
提前致谢,
答案 0 :(得分:2)
这是一个使用递归的快速而脏的方法。我们的想法是,要生成长度为k
且总和为n
的所有向量,您首先生成长度为k-1
的向量,每个向量n-i
为i=1..n
,然后在每个结尾添加一个额外的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
修改强>
正如评论中所提到的,这会遇到大型n
和k
的内存问题。流传输解决方案是优选的,其一次一个地生成输出。在像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中它肯定是可能的,但我将翻译留给你了!
答案 1 :(得分:1)
这是一次生成所有向量的一种可能方法(会给中等大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
为了避免内存问题,最好根据需要生成每个向量,而不是最初生成所有向量。以下方法迭代一个n
循环中的所有可能for
- 向量(无论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