我有五个元素A
,B
,C
,D
和E
。
每个元素之间的距离由下面的矩阵给出:
Distances =
[0 5 3 8 15;
5 0 7 5 20;
3 7 0 12 12;
8 5 12 0 8;
7 20 12 8 0]
我想选择所有元素组合,使得距离之和小于10
。
可以通过以下方式递归完成:
为上述示例手动完成我得到以下组合:
A,
B,
C,
D,
E,
A B,
A C,
A D,
B C,
B D,
D E,
A B C
如果元素的数量很大(比如250),我如何在Octave中系统地执行此操作?
答案 0 :(得分:1)
几个一般要点:
A->C + B->D
)方面没有什么意义,因为在问题中没有明确指定为无效,下面的解决方案也会输出它们。 250
个节点的可读结果,(即将节点“名称”从字母更改为数字,以查看26 < 250
的方式。)
function q41308927
%% Initialization:
nodes = char((0:4) + 'A');
D = [0 5 3 8 15;
5 0 7 5 20;
3 7 0 12 12;
8 5 12 0 8;
7 20 12 8 0];
thresh = 10;
d = triu(D); % The problem is symmetric (undirected), so we only consider the upper half.
% Also keep track of the "letter form":
C = reshape(cellstr(VChooseKRO(nodes,2)), size(D)).'; % "C" for "Combinations"
%{
C =
5×5 cell array
'AA' 'AB' 'AC' 'AD' 'AE'
'BA' 'BB' 'BC' 'BD' 'BE'
'CA' 'CB' 'CC' 'CD' 'CE'
'DA' 'DB' 'DC' 'DD' 'DE'
'EA' 'EB' 'EC' 'ED' 'EE'
%}
C = C(d>0); d = d(d>0);
assert(numel(C) == numel(d)); % This is important to check
%% Find eligible sets of size n
for k = 1:numel(nodes)
if numel(d)<k
break
end
% Enumerate combinations:
C = C(VChooseK(1:numel(C),k));
d = sum(VChooseK(d,k),2);
% Filter combinations:
if any(d < thresh)
C(d >= thresh,:) = [];
d = d(d < thresh);
disp(sortrows(C)); % This is just to show it works like the manual example
else
break
end
end
以上的输出是:
'AB'
'AC'
'AD'
'BC'
'BD'
'DE'
'AB' 'AC'
'AC' 'BD'
答案 1 :(得分:0)
这是一个简单的Octave(或Matlab)解决方案。矩阵a
与问题中的一样。该算法构建0-1矩阵limit
,其中每列编码一组距离小于a
的集合(例如10)。
矩阵c = a(:,m);
用identity初始化,因为所有单元素子集都是可接受的(距离之和为0)。然后挑选每列cand = c; cand(k) = 1;
并调查添加另一个元素的可能性(cand'*Distances*cand
表示添加第k个元素)。不失一般性,只考虑在集合的最后一个当前元素之后添加元素就足够了。
产品cand
是候选集a = [a cand];
距离总和的两倍。因此,如果它小于限制的两倍,则添加列:a
。最后,为了便于阅读,矩阵limit = 10;
n = length(Distances);
a = eye(n, n);
col1 = 1;
col2 = n;
while (col1 <= col2)
for m = col1:col2
c = a(:,m);
for k = max(find(c>0))+1:n
cand = c;
cand(k) = 1;
if cand'*Distances*cand < 2*limit
a = [a cand];
end
end
end
col1 = col2 + 1;
col2 = length(a);
end
disp(a')
以换位形式显示。
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
1 1 0 0 0
1 0 1 0 0
1 0 0 1 0
0 1 1 0 0
0 1 0 1 0
0 0 0 1 1
输出:
limit
使用250 x 250矩阵,性能将在很大程度上取决于for m = 1:length(a)
disp(find(a(:,m))')
end
的大小。如果它太大以至于所有或大部分2 ^ 250套合格,那么这将耗尽内存。 (2 ^ 250超过10 ^ 75,所以我认为你不想看到那么多套的附近)。
这是以更易读的形式输出:
1
2
3
4
5
1 2
1 3
1 4
2 3
2 4
4 5
输出:
Columns("f").EntireColumn.Hidden = Not CheckBox2.Value
Columns("g").EntireColumn.Hidden = Not CheckBox3.Value
Columns("h").EntireColumn.Hidden = Not CheckBox4.Value