方法#1:所有可能组合的迭代“蛮力”
以下是说明如何解决问题的一种可能算法。代码本身应该是不言自明的,但我们的想法是我们测试所有可能的列表组合,直到找到一个有效的组合(因此我们不会遇到您描述的问题,即我们错误地根据列表长度选择列表)。
function varargout = q36323802
R = [0 1 2 3 4 5 6 7 8 9]; %// Reference List
L = {... // As per Dan's suggestion:
[0 1 3 5 6 7 9]
[0 1 2 3 4]
[5 6 7 8 9]
[1 2 3 4]
[1 5 7 8]
};
out = []; %// Initialize output
%% // Brute-force approach:
nLists = numel(L);
for indN = 1:nLists
setCombinationsToCheck = nchoosek(1:nLists,indN);
for indC = 1:size(setCombinationsToCheck,1)
u = unique(cat(2,L{setCombinationsToCheck(indC,:)}));
if all(ismember(R,u))
out = setCombinationsToCheck(indC,:);
disp(['The minimum number of required sets is ' num2str(indN) ...
', and their indices are: ' num2str(out)]);
return;
end
end
end
disp('No amount of lists found to cover the reference.');
if nargout > 0
varargout{1} = out;
end
对于您的示例,输出为:
The minimum number of required sets is 2, and their indices are: 2 3
笔记):
- 此方法通过不使用
n-1
迭代中的长度列表来进行一些冗余计算,这些列表n
已经在之前的迭代中找到(如果适用)。在这种情况下,递归解决方案可能会起作用。
- 可能有一种方法可以对此进行矢量化,但我并没有真正深入考虑。
- 我假设所有输入都是行向量。如果不是这种情况,就必须采取一些额外的步骤。
感谢Adiel提出一些改进建议,感谢Amro发现一些错误!
方法#2:树搜索实验
我还尝试构建一个递归求解器。现在它找到了解决方案,但它不够通用(实际上问题是它只返回第一个结果,不一定是最好的结果)。这种方法背后的原因是我们可以将您的问题视为树搜索问题,因此我们可以使用搜索/寻路算法(请参阅BFS、DFS、IDS等)。我认为下面的算法最接近 DFS。和以前一样,这应该主要说明解决问题的方法。
function q36323802_DFS(R,L)
%% //Input checking:
if nargin < 2 || isempty(L)
L = {... // As per Dan's suggestion:
[0 1 3 5 6 7 9]
[0 1 2 3 4]
[5 6 7 8 9]
[1 2 3 4]
[1 5 7 8]
};
end
if nargin < 1 || isempty(R)
R = [0 1 2 3 4 5 6 7 8 9]; %// Reference List
end
%% // Algorithm (DFS: breadth-first search):
out = DFS_search(R,L,0);
if isempty(out)
disp('No amount of lists found to cover the reference.');
else
disp(['The minimum number of required sets is ' num2str(numel(out)) ...
', and their indices are: ' num2str(out)]);
end
end
function out = DFS_search(R,L,depth)
%// Check to see if we should stop:
if isempty(R) || isempty(L)
% // Backtrack here?
out = [];
return;
end
if isnan(R)
out = [];
return;
end
nLists = numel(L);
reducedR = cellfun(@(R,L)setdiff(R,L),repmat({R},[nLists,1]),L,'UniformOutput',false)';
%'// We consider a case where the reduction had no effect as "hopeless" and
%// "drop" it.
isFullCoverage = cellfun(@isempty,reducedR);
isHopeless = cellfun(@(R)all(isnan(R)),reducedR) | cellfun(@(rR)isequal(rR,R),reducedR);
reducedR(isHopeless) = deal({NaN});
if all(isHopeless) && ~any(isFullCoverage)
out = [];
return
end
if any(isFullCoverage) %// Check current "breadth level"
out = find(isFullCoverage,1,'first');
return
else
for indB = 1:nLists
out = DFS_search(reducedR{indB},L,depth+1);
if ~isempty(out)
out = [indB out]; %#ok
%// TODO: test if one of the sets is covered by the others and remove it
%// from the list "out".
%// Also, keep track of the best path and only return (finally) if shortest
return
end
end
end
end