在Matlab中生成包含给定集合中至少一个元素的所有组合
Posted
技术标签:
【中文标题】在Matlab中生成包含给定集合中至少一个元素的所有组合【英文标题】:Generating all combinations containing at least one element of a given set in Matlab 【发布时间】:2011-04-30 04:02:50 【问题描述】:我使用combnk
生成组合列表。如何生成始终包含特定值的组合子集。例如,对于combnk(1:10, 2)
,我只需要包含 3 和/或 5 的组合。有快速的方法吗?
【问题讨论】:
如果你不太受性能限制,你可以暴力破解,即创建大量组合,然后只选择好的组合。 【参考方案1】:好吧,在您的具体示例中,从集合 1, ..., 10 中选择两个整数,使得所选整数之一是 3 或 5 产生 9+9-1 = 17 个已知组合,因此您可以只是枚举它们。
一般来说,要从包含整数 m 的整数 1, ..., n 中找到所有 n-choose-k 组合,这与找到 (n-1)-choose-(k -1) 整数 1, ..., m-1, m+1, ..., n 的组合。
在 matlab 中是这样的
combnk([1:m-1 m+1:n], k-1)
(即使m
为 1 或 n,此代码仍然有效。)
【讨论】:
【参考方案2】:对于强力解决方案,您可以使用COMBNK 生成所有组合,然后使用函数ANY 和ISMEMBER 仅查找包含一个或多个数字子集的那些组合。以下是使用上述示例的方法:
v = 1:10; %# Set of elements
vSub = [3 5]; %# Required elements (i.e. at least one must appear in the
%# combinations that are generated)
c = combnk(v,2); %# Find pairwise combinations of the numbers 1 through 10
rowIndex = any(ismember(c,vSub),2); %# Get row indices where 3 and/or 5 appear
c = c(rowIndex,:); %# Keep only combinations with 3 and/or 5
编辑:
对于更优雅的解决方案,它看起来像Steve,我也有类似的想法。但是,我已经对解决方案进行了概括,使其既适用于任意数量的必需元素,也适用于v
中的重复元素。函数 SUBCOMBNK 将查找从集合 v
中提取的所有 k
值组合,其中至少包括集合 vSub
中的一个值:
function c = subcombnk(v,vSub,k)
%#SUBCOMBNK All combinations of the N elements in V taken K at a time and
%# with one or more of the elements in VSUB as members.
%# Error-checking (minimal):
if ~all(ismember(vSub,v))
error('The values in vSub must also be in v.');
end
%# Initializations:
index = ismember(v,vSub); %# Index of elements in v that are in vSub
vSub = v(index); %# Get elements in v that are in vSub
v = v(~index); %# Get elements in v that are not in vSub
nSubset = numel(vSub); %# Number of elements in vSub
nElements = numel(v); %# Number of elements in v
c = []; %# Initialize combinations to empty
%# Find combinations:
for kSub = max(1,k-nElements):min(k,nSubset)
M1 = combnk(vSub,kSub);
if kSub == k
c = [c; M1];
else
M2 = combnk(v,k-kSub);
c = [c; kron(M1,ones(size(M2,1),1)) repmat(M2,size(M1,1),1)];
end
end
end
您可以针对上面的蛮力解决方案测试此函数,以查看它返回相同的输出:
cSub = subcombnk(v,vSub,2);
setxor(c,sort(cSub,2),'rows') %# Returns an empty matrix if c and cSub
%# contain exactly the same rows
我使用v = 1:15;
和vSub = [3 5];
进一步针对蛮力解决方案测试了这个函数,N
的值范围从 2 到 15。创建的组合是相同的,但 SUBCOMBNK 明显更快,如平均运行所示时间(以毫秒为单位)显示如下:
N | brute force | SUBCOMBNK
---+-------------+----------
2 | 1.49 | 0.98
3 | 4.91 | 1.17
4 | 17.67 | 4.67
5 | 22.35 | 8.67
6 | 30.71 | 11.71
7 | 36.80 | 14.46
8 | 35.41 | 16.69
9 | 31.85 | 16.71
10 | 25.03 | 12.56
11 | 19.62 | 9.46
12 | 16.14 | 7.30
13 | 14.32 | 4.32
14 | 0.14 | 0.59* #This could probably be sped up by checking for
15 | 0.11 | 0.33* #simplified cases (i.e. all elements in v used)
【讨论】:
【参考方案3】:只是为了改进史蒂夫的答案:在你的情况下(你想要所有与 3 和/或 5的组合)它将是
所有 k-1/n-2 组合加上 3 个添加 所有 k-1/n-2 组合,添加 5 个 添加了 3 和 5 的所有 k-2/n-2 组合对于这种类型的任何其他情况很容易推广。
【讨论】:
以上是关于在Matlab中生成包含给定集合中至少一个元素的所有组合的主要内容,如果未能解决你的问题,请参考以下文章