问题陈述:让S
成为一组整数,例如S = {1,2,...,12}
。 M
是一个整数矩阵,其行可以被视为S
的子集,其长度除以S
的元素数,特别是M
的每一行只包含不同的元/整数。我正在尝试生成Matlab代码,该代码可以识别M
的所有不相交行组,其集合理论联合给出S
(即具有固定大小的子集中的S
分区)和将每个这样的组作为矩阵返回。
示例: A = [1 2 5 6; 3 4 11 12; 9 10 7 8]
是S
的分区,而B = [1 2 3 4; 5 6 7 8; 9 10 11 12; 1 5 9 12]
不是S
的分区(因为最后一行不是与之前的3)脱节。
数量级:通常情况下,M
会有~500 000行,而S
最多会有100个元素。
方法:让m = size(M,1)
,n = size(M,2)
(分区子集的大小),s = |S|
(要分区的集合的大小)和{ {1}}(形成分区所需的不相交行数 - 您可以假设k = s/n
,因此问题定义明确)。请注意,为了建立这样的分区,只需要检查行的不相交性,并且确实有s = 0 mod n
个行。
对于k
,我观察j = 1:(m-k+1)
,它给出了ind = (sum(ismember(M((j+1):m,:),M(j,:)),2)==0)
之后也与之不相交的行的索引列。然后,我通过将M(j,:)
与每个行组合来创建2 x n
矩阵。在那之后,我想用所有这些新的M(j,:)
矩阵重复ismember()
例程并继续重复,直到我得到2 x n
矩阵。这可能都是好事和花花公子,但它也是我绊倒的地方,因为,对于一个,k x n
- 例程的数量取决于for
。
问题:
(Q1)如何完成我的方法代码?
(Q2)是否有更好的方法解决这个问题(即更快,矢量化/更少k
循环,GPU辅助),如果是,它们是什么?
答案 0 :(得分:2)
这个问题是exact cover的一个非常特殊的情况。如果你在C中工作,我会建议使用Knuth's Algorithm X而不是bit arrays来实施dancing links,因为您关心的实例的密度明显。我希望MATLAB几乎可以容纳你。
作为整数,集合{1,2,5,6}可以表示为2 ** 1 + 2 ** 2 + 2 ** 5 + 2 ** 6。然后两个集合的交集表示为它们的表示的bitwise and,并且两个集合的并集是按位或。空集为0.不幸的是,对于S = 100,您需要使用两个或更多个整数,这会使生命复杂化。拍摄集合后,您可以通过矢量化bitand
检测与其他集合的交叉点。
答案 1 :(得分:0)
perms
以获取nchoosek
返回的每一行的所有可能排列。
我不得不使用递归函数,所以你必须把它放在一个文件中:
function test()
s = 1:6;
n = 2;
M_all = ProcessOneRow(s, n, {}, {});
disp('All possilbe M:')
M_all
end
function M_all = ProcessOneRow(s, n, cRows, M_all)
%// find all possible rows for this level
possibleRows = nchoosek(1:length(s), n);
for t=1:size(possibleRows, 1)
%// keep track of all rows so far
cRows(end+1) = s(possibleRows(t,:));
%// get elements remaining (remove this row)
s_sub = s;
s_sub(possibleRows(t,:)) = [];
if isempty(s_sub)
%// We found a new complete matrix M
M = [];
for p = 1:numel(cRows)
M(p,:) = cRows{p};
end
M_all{end+1} = M;
else
%// Still not a complete M, so we process the rest
M_all = ProcessOneRow(s_sub, n, cRows, M_all);
end
cRows(end) = [];
end
end