查找满足某些条件的一组向量的子集

时间:2014-12-15 23:21:16

标签: algorithm matlab matrix

在我对这个问题进行的所有评论之后,我做了一些修改,使其更清晰,更简单。

要解决此问题,我有一个矩阵A和一个行向量A(1,2:7)(行参考),其中至少包含一个0

从矩阵A

A=[1   2 0 1 2 0 0   0
   2   1 1 1 0 2 2   0
   3   0 0 0 0 1 1   1
   4   0 2 0 1 1 1   2
   5   0 0 0 0 0 1   0
   6   1 0 1 1 2 0   2
   7   1 1 2 2 2 1   1
   8   0 1 1 2 2 0   0
   9   0 1 1 2 2 0   0
  10   2 2 2 2 0 0   1]

除了A(k,2:7),k≠1 and A(k,8)=0之外,我想找到一个或者如果可能的所有向量A(1,2:7)组合,它们满足以下条件:

  1. 组合仅由满足的矢量形成 A(k,8)=0; k=1,..,10

  2. 我不会在结果中考虑A(7,2:7),因为它不包含任何0。

  3. 如果{A(1,2:7),A(j,2:7)}是给定的组合,这意味着 A(1,n)≠0A(j,n)≠0n = 2,...,7A。 (至少有一个 应该是0中同一列上的两个值 与{A(1,2:7),A(j,2:7),A(p,2:7)})不同

  4. 一个组合可以包含两个或更多个向量。另一个例子: 如果A(1,n)≠0是给定的组合,这意味着 A(j,n)≠0的{​​{1}}或A(p,n)≠0n = 2,...,7的{​​{1}}。 (三个值中的至少一个是相同的 A中的列应与0

  5. 不同
  6. 对于矩阵A{A(1,2:7),A(2,2:7)}是一个组合 满足期望的条件。但我不想拥有 自{A(1,2:7),A(2,2:7),A(3,2:7)}以来A(1,2:7)组合A(2,2:7) A(1,2:7)足以构成一个组合。

  7. 对于向量组合,我必须将一个向量作为参考,在这种情况下,它是向量A(1,2:7)。这是我们想要补偿它们的零的向量。因此A(1,2:7)通过其非零组件为关联做出贡献:2,1和2.

    当我在上面说“除了A(1,2:7)之外我想找...”时,A(5,2:7)是行引用时这是有效的。但如果A(5,2:7)是行引用,则在这种情况下,句子变为“除了A之外”。

    对于我的真实问题700x8是一个A矩阵。此处A(1,2:7)A(7,2:7)A(k,2:7)只是一个示例,我更喜欢矩阵A的任意向量A(k,8)=0的解决方案,0至少其中一个组成部分是{{1}}。

2 个答案:

答案 0 :(得分:4)

问题有点复杂,难以理解..无论如何,我尝试编写一些代码,以便最好地理解问题。以下是找到可能组合的部分:

% input matrix
A=[1   2 0 1 2 0 0   0
   2   1 1 1 0 2 2   0
   3   0 0 0 0 1 1   1
   4   0 2 0 1 1 1   2
   5   0 0 0 0 0 1   0
   6   1 0 1 1 2 0   2
   7   1 1 2 2 2 1   1
   8   0 1 1 2 2 0   0
   9   0 1 1 2 2 0   0
  10   2 2 2 2 0 0   1];

% start by considering all rows
rowsIndices = (1:size(A,1))';
rIdx = true(size(rowsIndices));

% exclude 7th row (i.e rows with no zeros in columns 2:7)
%idx(~any(A(:,2:7)==0,2)) = false;
rIdx(7) = false;

% exclude rows that dont have zero in column 8
rIdx(A(:,8) ~= 0) = false;

% for each possible n-combinations
N = sum(rIdx);
combs = cell(1,N);
for k=2:N
    % all combinations of k-rows
    combsK = nchoosek(rowsIndices(rIdx), k);

    % must involve first row
    combsK = combsK(any(combsK==1,2),:);

    % exclude from current k-combinations if there are smaller ones
    if k > 2
        combsKIdx = true(size(combsK,1),1);
        for kk=2:k-1
            if isempty(combs{kk}), continue, end
            for i=1:size(combs{kk},1)
                combsKIdx(sum(ismember(combsK,combs{kk}(i,:)),2)==kk) = false;
            end
        end
        combsK = combsK(combsKIdx,:);
    end

    % for every possible combination, each column 2:7 must not be all zeros
    combsKIdx = true(size(combsK,1),1);
    for i=1:size(combsK,1)
        combsKIdx(i) = all(any(A(combsK(i,:),2:7),1));
    end
    combsK = combsK(combsKIdx,:);

    % store combinations found
    combs{k} = combsK;
end

% display results
celldisp(combs)

以下是我得到的组合:

combs{1} =
     []
combs{2} =
     1     2
combs{3} =
     1     5     8
     1     5     9
combs{4} =
     []
combs{5} =
     []

换句话说三种组合;首先是行[1 2],第二个[1 5 8],第三行是行[1 5 9]。

我遗漏的部分是计算"分数"的最后一步。发现的每种组合。老实说,我不明白,描述令人困惑!所以我会把那部分留给你......

答案 1 :(得分:1)

如果我正确地理解了对此处要求的令人难以置信的过于复杂的描述,那么您需要:

  • 包含一个特定参考行的最小行集
  • 在最后一列中都有一个零,在'data'列中至少有一个零
  • 使得这组行一起在每个“数据”列中包含至少一个非零元素
    • 然后用结果索引进行一些调整

由于我最近几天在类似的事情上工作,这是好的和新鲜的。这是一个简单的暴力方法 - 如果需要考虑更大数据的效率,需要更换前面生成的所有组合(我最终编写了一个递归迭代器,它为每个组合调用一个回调函数,但我会留下这里为了简单起见)。我假设第一列将始终包含相关的原始索引 - 根据示例 - 这使得在不丢失轨道的情况下将数据拉开很容易,并且拉开数据有助于简化逻辑。

示例设置:

A=[1   2 0 1 2 0 0   0
   2   1 1 1 0 2 2   0
   3   0 0 0 0 1 1   1
   4   0 2 0 1 1 1   2
   5   0 0 0 0 0 1   0
   6   1 0 1 1 2 0   2
   7   1 1 2 2 2 1   1
   8   0 1 1 2 2 0   0
   9   0 1 1 2 2 0   0
  10   2 2 2 2 0 0   1];
% data columns
colidx = 2:7;
% reference row
refidx = 1;
indices = findindices(A, refidx, colidx)
% then muck about with the indices as need be

功能:

function indices = findindices(A, refidx, colidx)
% pick out the relevant rows
setidx = (A(:,8) == 0) & ~all(A(:,colidx), 2) & (A(:,1) ~= refidx);
ref = A(refidx, :);
rows = A(setidx, :);
% no need to pass any more than the columns of interest here
c = findcombination(ref(colidx), rows(:,colidx));
% turn the combination of 'rows' indices back into the original ones,
indices = [ref(1); rows(c, 1)];
end

function c = findcombination(ref, rows)
n = size(rows, 1);
% search all 1-combinations first, then 2-combinations, etc.
% to ensure we find the smallest first.
for k=1:n
    for c = nchoosek(1:n, k)'
        set = [ref; rows(c,:)];
        if any(set, 1) % true if all columns have at least one nonzero
            return;   % c contains the combination in terms of the rows array
        end
    end
end
c = [];
error('no valid combination!')
end

示例数据的结果:

>> test

indices =

    1
    2