我有一个矩阵如下:
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
完成此操作后,循环浏览所有可能的组合。 我想知道是否有更简单的方法。
答案 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)