在Matlab中查找可能的对的所有可能“列表”

时间:2014-03-19 09:33:58

标签: matlab

过去几天我一直在考虑一个问题,但由于我是MATLAB的初学者,我不知道如何解决它。这是背景。假设您有一个对称N×N矩阵,其中每个元素都是01N = (1,2,...,n)

例如:

A =

    0     1     1     0

    1     0     0     1

    1     0     0     0

    0     1     0     0

如果A(i,j) == 1,则可以形成货币对(i,j),如果A(i,j)==0,则无法形成货币对(i,j)。例如,(1,2)是一对可能的对,A(1,2)==A(2,1)==1(3,4)不是A(3,4)==A(4,3)==0的可能对。

这是问题所在。假设集合N中的成员只能与集合中最多一个其他不同成员N成对(即,如果1与2形成一对,那么1不能形成一对3)。如何找到可能对的所有可能“列表”?在上面的示例中,一个“列表”仅包含(1,2)对。如果形成该对,则不可能形成任何其他对。另一个“列表”是:((1,3),(2,4))。我搜索了论坛,发现后者“列表”是可以找到的最大匹配,例如,通过使用二分图方法。但是,我不一定只对找到最大匹配感兴趣;我有兴趣找到所有可能的“列表”。 另一个例子:

A =

    0     1     1     1

    1     0     0     1

    1     0     0     0

    1     1     0     0

在此示例中,有三个可能的列表:

   (1,2)
   ((1,3),(2,4))
   (1,4)

我希望你能理解我的问题,如果不清楚我会道歉。我感谢所有帮助。非常感谢!

2 个答案:

答案 0 :(得分:1)

这可能是一种快速的方法。

<强>代码

%// Given data, A
A =[ 0 1 1 1;
    1 0 0 1;
    1 0 0 0;
    1 1 0 0];

%%// The lists  will be stored in 'out' as a cell array and can be accessed as out{1}, out{2}, etc.
out = cell(size(A,1)-1,1);

%%// Code that detects the lists using "selective" diagonals
for k = 1:size(A,1)-1
    [x,y] = find(triu(A,k).*(~triu(ones(size(A)),k+1)));
    out(k) = {[x y]};
end
out(cellfun('isempty',out))=[]; %%// Remove empty lists

%%// Verification - Print out the lists
for k = 1:numel(out)
    disp(out{k})
end

<强>输出

 1     2

 1     3
 2     4

 1     4

编辑1

基本上我会计算矩阵的所有成对指数,以满足问题中设定的标准,然后简单地将它们映射到给定的矩阵上。找到“有效”指数的部分显然是其中的繁琐部分,并且在处理大于10的输入矩阵时,采用一些积极方法的代码也很昂贵。

<强>代码

%// Given data, A
A = [0 1 1 1; 1 0 1 1; 1 1 0 1; 1 1 1 0]

%%// Get all pairwise combinations starting with 1
all_combs = sortrows(perms(1:size(A,1)));
all_combs = all_combs(all_combs(:,1)==1,:);

%%// Get the "valid" indices
all_combs_diff = diff(all_combs,1,2);
valid_ind_mat = all_combs(all(all_combs_diff(:,1:2:end)>0,2),:);
valid_ind_mat = valid_ind_mat(all(diff(valid_ind_mat(:,1:2:end),1,2)>0,2),:);

%%// Map the ones of A onto the valid indices to get the lists in a matrix and then cell array
out_cell = mat2cell(valid_ind_mat,repmat(1,[1 size(valid_ind_mat,1)]),repmat(2,[1 size(valid_ind_mat,2)/2]));
A_masked = A(sub2ind(size(A),valid_ind_mat(:,1:2:end),valid_ind_mat(:,2:2:end)));
out_cell(~A_masked)={[]};

%%// Remove empty lists
out_cell(all(cellfun('isempty',out_cell),2),:)=[];

%%// Verification - Print out the lists
disp('Lists =');
for k1 = 1:size(out_cell,1)
    disp(strcat('  List',num2str(k1),':'));
    for k2 = 1:size(out_cell,2)
        if ~isempty(out_cell{k1,k2})
            disp(out_cell{k1,k2})
        end
    end
end

<强>输出

A =

     0     1     1     1
     1     0     1     1
     1     1     0     1
     1     1     1     0

Lists =
  List1:
     1     2

     3     4

  List2:
     1     3

     2     4

  List3:
     1     4

     2     3

答案 1 :(得分:0)

我确信有更快的方法,但这是明显的解决方案:

%// Set top half to 0, and find indices of all remaining 1's
A(triu(A)==1) = 0;
[ii,jj] = find(A);

%// Put these in a matrix for further processing
P = [ii jj];

%// Sort indices into 'lists' of the kind you defined 
X = repmat({}, size(P,1),1);
for ii = 1:size(P,1)-1
    X{ii}{1} = P(ii,:);
    for jj = ii+1:size(P,1)
        if ~any(ismember(P(ii,:), P(jj,:)))
            X{ii}{end+1} = P(jj,:); end
    end
end