Matlab得到的所有可能组合都小于一个值

时间:2017-07-05 13:17:49

标签: matlab

我有一个矩阵如下:

id      value
=============
 1       0.5
 2       0.5
 3       0.8
 4       0.3
 5       0.2

从这个数组中,我希望找到所有可能的总和小于或等于1的组合。也就是说,

result
======
1 2
1 4 5
2 4 5
3 5
1 5
1 4
2 4
2 5
...

为了得到上述结果,我的想法是最初计算查找数组中元素总和的所有可能性,如下所示:

for ii = 1 : length(a) % compute number of possibilities 
     no_of_possibilities = no_of_possibilities + nchoosek(length(a),ii);
end

完成此操作后,循环浏览所有可能的组合。 我想知道是否有更简单的方法。

3 个答案:

答案 0 :(得分:2)

data = [0.5, 0.5, 0.8, 0.3, 0.2];
required = cell(1, length(data));
subsets = cell(1, length(data));
for k = 2:length(data)-1 % removes trivial cases (all numbers or one number at a time)
    % generate all possible k-pairs (if k = 3, then all possible triplets
    % will be generated)
    combination = nchoosek(1:length(data), k);
    % for every triplet generated, this function sums the corresponding
    % values and then decides whether then sum is less than equal to 1 or
    % not
    findRequired = @(x) sum(data(1, combination(x, :))) <= 1;
    % generate a logical vector for all possible combinations like [0 1 0]
    % which denotes that the 2nd combination satisfies the condition while
    % the others do not
    required{k} = arrayfun(findRequired, 1:size(combination, 1));
    % access the corresponding combinations from the entire set
    subsets{k} = combination(required{k}, :);
end

这会产生以下子集:

1     2
1     4
1     5
2     4
2     5
3     5
4     5
1     4     5
2     4     5

答案 1 :(得分:1)

这不是一种简单的方法,但是更快的方式,因为我删除了其子集未通过条件的组合。

bitNo = length(A);         % number of bits
setNo = 2 ^ bitNo - 1;     % number of sets
subsets = logical(dec2bin(0:setNo, bitNo) - '0'); % all subsets
subsets = subsets(2:end,:); % all subsets minus empty set!
subsetCounter = 1;
resultCounter = 1;
result = {};
while(1)
    if( subsetCounter >= size(subsets,1))
         break;
    end
    if(sum(A(subsets(subsetCounter,:).',2)) <= 1)
         result{resultCounter} = A(subsets(subsetCounter,:).',1).';
         resultCounter = resultCounter + 1;
         subsetCounter = subsetCounter + 1;
    else
         % remove all bad cases related to the current subset
         subsets = subsets(sum((subsets & subsets(subsetCounter,:)) - subsets(subsetCounter,:),2) ~= 0,:);
    end       
end

使用此method生成子集。之后,检查每个子集的条件。如果子集未通过条件,则从子集中删除其所有超集。为此,使用sum((subsets & subsets(i,:)) - subsets(i,:),2) ~= 0意味着从subsets获取一些行,这些行与未传递的子集的元素不同。通过这样做,我们不能再考虑一些不良案例了。虽然理论上这个代码是Θ(2 ^ n)

答案 2 :(得分:0)

这是潜在的解决方案,使用低效的步骤,但从各种SO答案中借用有效的代码。归功于那些原始的窥视。

data = [0.5, 0.5, 0.8, 0.3, 0.2];

首先获取所有索引组合,不一定使用所有值。

combs = bsxfun(@minus, nchoosek(1:numel(data)+numel(data)-1,numel(data)), 0:numel(data)-1);

然后去掉每个组合中的重复索引,无论索引顺序如何

[ii, ~, vv] = find(sort(combs,2));
uniq = accumarray(ii(:), vv(:), [], @(x){unique(x.')});

接下来获得独特的组合,无论索引顺序如何......注意:通过重组步骤,您可以更有效地执行此步骤,但它会这样做。

B = cellfun(@mat2str,uniq,'uniformoutput',false);
[~,ia] = unique(B);
uniq=uniq(ia);

现在根据索引组合的单元格数组(data)对uniq中的所有值进行求和

idx = cumsum(cellfun('length', uniq));
x = diff(bsxfun(@ge, [0; idx(:)], 1:max(idx)));
x = sum(bsxfun(@times, x', 1:numel(uniq)), 2);  %'// Produce subscripts
y = data([uniq{:}]);                               % // Obtain values
sums_data = accumarray(x, y);

最后只保留总和为&lt; = 1

的索引组合
allCombLessThanVal = uniq(sums_data<=1)