查找距离总和小于给定数量的有限度量空间的所有子集

时间:2016-12-23 23:31:45

标签: matlab combinations octave path-finding undirected-graph

我有五个元素ABCDE

每个元素之间的距离由下面的矩阵给出:

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

可以通过以下方式递归完成:

  • 首先找到一组符合2项资格的组合。
  • 然后,通过向之前找到的符合条件的2项组合添加其他项目来查找3项符合条件的组合。

为上述示例手动完成我得到以下组合:

A,  
B,  
C,  
D,  
E,  
A   B,
A   C,
A   D,
B   C,
B   D,
D   E,  
A   B   C

如果元素的数量很大(比如250),我如何在Octave中系统地执行此操作?

2 个答案:

答案 0 :(得分:1)

几个一般要点:

  • 由于原始问题标有,我将展示我在那里测试的解决方案。
  • 此解决方案使用FEX上的函数VChooseKVChooseKRO,需要使用适当的编译器将其编译到MEX中。
  • 即使问题涉及距离,并且在添加不连续路径(即A->C + B->D)方面没有什么意义,因为在问题中没有明确指定为无效,下面的解决方案也会输出它们。
  • 针对OP中给出的示例显示了解决方案。应略微修改它以输出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